题目链接:

luogu1600

谨以此题纪念那段年少无知但充满趣味的恬淡时光

附上一位dalao的博客链接:https://www.luogu.org/blog/user26242/ke-pa-di-tian-tian-ai-pao-bu

我写这道题的时候脑袋里一直想的是他还没AFO的时候的那段日子,真是快乐啊,虽然我那时什么都不会

好了废话结束

他写的是最为常见的差分+\(LCA\)+桶的写法,在此不再赘述

其实这是一道线段树合并的基础题

常规套路:我们将路径\((s,t)\)拆成\((s,lca)\)和\((lca,t)\),在这两段路径中

1)如果在\((s,lca)\)上的一点\(i\)看到,则\(w_i=dep_s-dep_i\),即\(w_i+dep_i=dep_s\)

2)如果在\((lca,t)\)上的一点\(i\)看到,则\(w_i=dep_s-dep_{lca}+dep_i-dep_{lca}\),即\(w_i-dep_i=dep_s-dep_{lca}*2\)

也就是说我们对于树上的某点\(i\),需要统计它的子树中满足上两个式子中某一个的点的个数

这个可以用权值线段树的合并维护

同时考虑到该路径不会对\(lca\)以上部分的答案产生影响,故考虑树上差分;具体的,在\(s\)和\(t\)处放上\(+1\)标记,而在\(fa_{lca}\)放上两个\(-1\)标记

代码注意事项

1)第二个式子中可能会出现负数,因此将值域整体向右平移\(n\)个单位

2)当这条路径的\(lca\)是一个可以被统计到答案的点时,它会被统计两次(带回发现它对两个式子均成立)。这可以在打\(tag\)时直接判断

代码如下(常数很大,luogu不吸氧\(5317ms\))

#include<iostream>
#include<string.h>
#include<string>
#include<stdio.h>
#include<algorithm>
#include<math.h>
#include<vector>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define lowbit(x) (x)&(-x)
#define rep(i,a,b) for (int i=a;i<=b;i++)
#define per(i,a,b) for (int i=a;i>=b;i--)
#define maxd 1000000007
typedef long long ll;
const int N=100000;
const double pi=acos(-1.0);
struct edgenode{
int to,nxt;
}sq[600200];
int n,m,all=0,head[300300],w[300300],dep[300300],fa[300300][20],ans[300300]; int read()
{
int x=0,f=1;char ch=getchar();
while ((ch<'0') || (ch>'9')) {if (ch=='-') f=-1;ch=getchar();}
while ((ch>='0') && (ch<='9')) {x=x*10+(ch-'0');ch=getchar();}
return x*f;
} struct segment_tree{
struct node{
int cnt,lson,rson;
}seg[10000800];
int tot,root[300100]; void insert(int &id,int l,int r,int pos,int val)
{
if (!id) id=(++tot);seg[id].cnt+=val;
if (l==r) return;
int mid=(l+r)>>1;
if (pos<=mid) insert(seg[id].lson,l,mid,pos,val);
else insert(seg[id].rson,mid+1,r,pos,val);
} int merge(int x,int y,int l,int r)
{
if ((!x) || (!y)) return x+y;
seg[x].cnt+=seg[y].cnt;
int mid=(l+r)>>1;
seg[x].lson=merge(seg[x].lson,seg[y].lson,l,mid);
seg[x].rson=merge(seg[x].rson,seg[y].rson,mid+1,r);
return x;
} int query(int id,int l,int r,int pos)
{
if (l==r) return seg[id].cnt;
int mid=(l+r)>>1;
if (pos<=mid) return query(seg[id].lson,l,mid,pos);
else return query(seg[id].rson,mid+1,r,pos);
}
}seg1,seg2; void add(int u,int v)
{
all++;sq[all].to=v;sq[all].nxt=head[u];head[u]=all;
} int query_lca(int u,int v)
{
if (dep[u]<dep[v]) swap(u,v);
int tmp=dep[u]-dep[v];
rep(i,0,19)
if ((tmp>>i)&1) u=fa[u][i];
if (u==v) return u;
per(i,19,0)
if (fa[u][i]!=fa[v][i]) {u=fa[u][i];v=fa[v][i];}
return fa[u][0];
} void dfs1(int u,int fu)
{
dep[u]=dep[fu]+1;fa[u][0]=fu;
rep(i,1,19) fa[u][i]=fa[fa[u][i-1]][i-1];
int i;
for (i=head[u];i;i=sq[i].nxt)
{
int v=sq[i].to;
if (v==fu) continue;
dfs1(v,u);
}
} void dfs2(int u,int fu)
{
int i;
for (i=head[u];i;i=sq[i].nxt)
{
int v=sq[i].to;
if (v==fu) continue;
dfs2(v,u);
seg1.root[u]=seg1.merge(seg1.root[u],seg1.root[v],0,n);
seg2.root[u]=seg2.merge(seg2.root[u],seg2.root[v],0,n*2);
}
if ((w[u]+dep[u]>=0) && (w[u]+dep[u]<=n))
ans[u]+=seg1.query(seg1.root[u],0,n,w[u]+dep[u]);
if ((w[u]-dep[u]>=-n) && (w[u]-dep[u]<=n))
ans[u]+=seg2.query(seg2.root[u],0,2*n,w[u]-dep[u]+n);
} int main()
{
n=read();m=read();
seg1.tot=0;seg2.tot=0;
rep(i,1,n-1)
{
int u=read(),v=read();
add(u,v);add(v,u);
}
dfs1(1,0);
rep(i,1,n) w[i]=read();
rep(i,1,m)
{
int s=read(),t=read(),lca=query_lca(s,t),fal=fa[lca][0];
seg1.insert(seg1.root[s],0,n,dep[s],1);
seg1.insert(seg1.root[fal],0,n,dep[s],-1);
seg2.insert(seg2.root[t],0,n*2,dep[s]-2*dep[lca]+n,1);
seg2.insert(seg2.root[fal],0,n*2,dep[s]-2*dep[lca]+n,-1);
if (w[lca]+dep[lca]==dep[s]) ans[lca]--;
}
dfs2(1,0);
rep(i,1,n) printf("%d ",ans[i]);
return 0;
}

[luogu1600]NOIp2016D1T2 天天爱跑步的更多相关文章

  1. [luogu1600 noip2016] 天天爱跑步 (树上差分)

    题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵 ...

  2. luogu1600 [NOIp2016]天天爱跑步 (tarjanLca+dfs)

    经过部分分的提示,我们可以把一条路径切成s到lca 和lca到t的链 这样就分为向上的链和向下的链,我们分开考虑: 向上:如果某一个链i可以对点x产生贡献,那么有deep[x]+w[x]=deep[S ...

  3. 【神仙题】【P1600】【NOIP2016D1T2】天天爱跑步

    传送门 Description 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游 ...

  4. UOJ261 【NOIP2016】天天爱跑步

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000作者博客:http://www.cnblogs.com/ljh2000-jump/转 ...

  5. BZOJ4719 [Noip2016]天天爱跑步

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000作者博客:http://www.cnblogs.com/ljh2000-jump/转 ...

  6. noip2016天天爱跑步

    题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 个结点 ...

  7. bzoj 4719: [Noip2016]天天爱跑步

    Description 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.?天天爱跑步?是一个养成类游戏,需要 玩家每天按时上线,完成打卡任务.这个游戏的地图可以看作一一 ...

  8. [NOIP]2016天天爱跑步

    [NOIP]2016天天爱跑步 标签: LCA 树上差分 NOIP Description 小C同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是 ...

  9. NOIP2016 天天爱跑步 80分暴力

    https://www.luogu.org/problem/show?pid=1600 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养 ...

随机推荐

  1. 对于jQuery的了解

    1.了解jQuery与JavaScript的区别 css --外貌特征Html --躯干,骨架js --运动神经 jQuery就是对JavaScript的一个拓展,封装,就是让JavaScript更好 ...

  2. [TCP/IP] 传输层-ethereal 抓包分析TCP包

    开启抓包工具抓取一个HTTP的GET请求,我的ip是10.222.128.159    目标服务器ip是140.143.25.27 握手阶段: 客户端 ===> SYN MSS=1460(我能接 ...

  3. 杂牌机搞机之旅(二)————移植TWRP第三方Recovery并刷入

    原本想把杂牌机作为android破解和开发的测试机,破解的话肯定是安装框架的嘛,毕竟有些是要涉及到脱壳 . 但是,我尝试安装xposed的时候,手机卡在了开机界面,也就是magisk出现了错误,如果想 ...

  4. python之循环(增删)内使用list.remove()

    dat=['] for item in dat: ': dat.remove(item) print(dat) #按要求是把'0'都删掉的,输出结果是['1', '2', '3', '0'] ?? 首 ...

  5. 大华门禁SDK二次开发(二)-SignalR应用

    经过与大华技术支持的沟通,门禁服务程序已经开发好了,可以正常接收门禁开关事件,可以发送开门命令.基于项目实时性要求,这里使用SignalR实现门禁状态.控制命令的实时传送. 几种场景需求 根据Sign ...

  6. arcgis api 3.x for js 入门开发系列十五台风轨迹

    前言 关于本篇功能实现用到的 api 涉及类看不懂的,请参照 esri 官网的 arcgis api 3.x for js:esri 官网 api,里面详细的介绍 arcgis api 3.x 各个类 ...

  7. C++设计模式视频讲解

    设计模式(C++) 视频网址: http://www.qghkt.com/ 设计模式(C++)视频地址: https://ke.qq.com/course/318637?tuin=a508ea62 目 ...

  8. WDS和DHCP配置说明

    网络启动程序 (NBP) 是网络启动过程中第一个下载和执行的文件,它可以控制启动开始时的体验(例如,用户是否必须按 F12 才能开始网络启动) WDS服务器配置说明: 1)如果WDS和DHCP安装在同 ...

  9. WPF软件开发系统之二——水环境检测Surface触摸屏软件开发

    该系统采用C#.WPF语言开发,开发工具Visual Studio 2015.Blend,环境WIN7系统及以上,适用于PC.Windows触摸屏Surface等设备. 部分截图效果如下: 开发工具环 ...

  10. python学习笔记2_条件循环和其他语句

    一.条件循环和其他语句 1.print和import的更多信息. 1.1.使用逗号输出  //print() 打印多个表达式是可行的,用逗号隔开.       在脚本中,两个print语句想在一行输出 ...