经过部分分的提示,我们可以把一条路径切成s到lca 和lca到t的链

这样就分为向上的链和向下的链,我们分开考虑:

向上:如果某一个链i可以对点x产生贡献,那么有deep[x]+w[x]=deep[S[i]],而且S[i]和lca[i]都在x的子树中

向下:如果某一个链i可以对点x产生贡献,那么有deep[x]-w[x]=deep[T[i]]-L[i],而且T[i]和lca[i]都在x的子树中,其中L[i]表示对应的路径的长度,即L[i]=deep[T[i]]+deep[S[i]]-2*deep[lca[i]]

这样的话,我们可以把deep[S[i]]和deep[T[i]]-L[i]在合适的时候放到对应的桶里,然后在合适的时候查桶里的值作为答案

具体来说,dfs一下,找到S(或T)的时候给对应的桶++,找到lca的时候给对应的桶--,在子树都做完以后统计答案

但只是这样的话,对于某些点,会出现某些链,lca在它的祖先上,但端点却在它的祖先的另一颗子树中,也就是会被这个点查到

我们只要在进入这个点的时候记下来进入时候对应的桶中的结果,再在回来的时候用现在的减掉刚才记下来的,就是答案,因为这样减出来的一定是在他子树里的

注意由于偷懒,lca实际上在这两个链里都算了一遍,如果lca会被它这个点统计到的话,需要减下去一次贡献

据说有差分的思想?我太菜了看不出来...

 #include<bits/stdc++.h>
#define pa pair<int,int>
#define lowb(x) ((x)&(-(x)))
#define REP(i,n0,n) for(i=n0;i<=n;i++)
#define PER(i,n0,n) for(i=n;i>=n0;i--)
#define MAX(a,b) ((a>b)?a:b)
#define MIN(a,b) ((a<b)?a:b)
#define CLR(a,x) memset(a,x,sizeof(a))
#define rei register int
using namespace std;
typedef long long ll;
const int maxn=3e5+; inline ll rd(){
ll x=;char c=getchar();int neg=;
while(c<''||c>''){if(c=='-') neg=-;c=getchar();}
while(c>=''&&c<='') x=x*+c-'',c=getchar();
return x*neg;
} struct Edge{
int a,b,ne;
}eg[maxn*];
int egh[maxn],ect;
int N,M,w[maxn],s[maxn],t[maxn];
int dep[maxn],lca[maxn],len[maxn],bfa[maxn];
int fa[maxn],que[maxn*][],qh[maxn];
int cntu[maxn],cntd[maxn*],ans[maxn];
int sid[maxn],sh[maxn],tid[maxn],th[maxn],lid[maxn],lh[maxn];
bool flag[maxn]; inline void adeg(int a,int b){
eg[++ect].a=a;eg[ect].b=b;eg[ect].ne=egh[a];egh[a]=ect;
}
inline int getf(int x){return x==bfa[x]?x:bfa[x]=getf(bfa[x]);} void dfs(int x){
flag[x]=;
for(int i=egh[x];i;i=eg[i].ne){
int b=eg[i].b;
if(flag[b]) continue;
dep[b]=dep[x]+;fa[b]=x;
dfs(b);
bfa[getf(b)]=getf(x);
}
for(int i=qh[x];i;i=que[i][]){
if(flag[que[i][]]) lca[i>>]=getf(que[i][]);
}
} void solve(int x,int f){
int su=cntu[dep[x]+w[x]],sd=cntd[dep[x]-w[x]+N];
for(int i=sh[x];i;i=sid[i]){
cntu[dep[s[i]]]++;
}for(int i=th[x];i;i=tid[i]){
cntd[dep[t[i]]-len[i]+N]++;
}
for(int i=egh[x];i;i=eg[i].ne){
int b=eg[i].b;
if(b==f) continue;
solve(b,x);
}
ans[x]=cntu[dep[x]+w[x]]+cntd[dep[x]-w[x]+N]-su-sd;
for(int i=lh[x];i;i=lid[i]){
cntu[dep[s[i]]]--;
cntd[dep[t[i]]-len[i]+N]--;
if(w[x]==dep[s[i]]-dep[lca[i]]) ans[x]--;
}
} int main(){
int i,j,k;
N=rd(),M=rd();
for(i=;i<N;i++){
int a=rd(),b=rd();
adeg(a,b);adeg(b,a);
}
for(i=;i<=N;i++) w[i]=rd();
for(i=;i<=M;i++){
s[i]=rd(),t[i]=rd();
que[i<<][]=s[i],que[i<<|][]=t[i];
que[i<<][]=qh[t[i]],que[i<<|][]=qh[s[i]];
qh[t[i]]=i<<,qh[s[i]]=i<<|;
}
for(i=;i<=N;i++) bfa[i]=i;
dfs();
for(i=;i<=M;i++){ sid[i]=sh[s[i]];sh[s[i]]=i;
tid[i]=th[t[i]];th[t[i]]=i;
lid[i]=lh[lca[i]];lh[lca[i]]=i;
len[i]=dep[t[i]]+dep[s[i]]-*dep[lca[i]];
}
solve(,);
for(i=;i<=N;i++) printf("%d ",ans[i]);
return ;
}

luogu1600 [NOIp2016]天天爱跑步 (tarjanLca+dfs)的更多相关文章

  1. [Noip2016]天天爱跑步 LCA+DFS

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

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

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

  3. [NOIP2016] 天天爱跑步 桶 + DFS

    ---题面--- 题解: 很久以前就想写了,一直没敢做,,,不过今天写完没怎么调就过了还是很开心的. 首先我们观察到跑步的人数是很多的,要一条一条的遍历显然是无法承受的,因此我们要考虑更加优美的方法. ...

  4. [NOIp2016]天天爱跑步 线段树合并

    [NOIp2016]天天爱跑步 LG传送门 作为一道被毒瘤出题人们玩坏了的NOIp经典题,我们先不看毒瘤的"动态爱跑步"和"天天爱仙人掌",回归一下本来的味道. ...

  5. 【LG1600】[NOIP2016]天天爱跑步

    [LG1600][NOIP2016]天天爱跑步 题面 洛谷 题解 考虑一条路径\(S\rightarrow T\)是如何给一个观测点\(x\)造成贡献的, 一种是从\(x\)的子树内出来,另外一种是从 ...

  6. NOIP2016天天爱跑步 题解报告【lca+树上统计(桶)】

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

  7. BZOJ4719 [Noip2016]天天爱跑步

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

  8. noip2016天天爱跑步

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

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

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

随机推荐

  1. windows下pwd、ls、tail-f命令使用

    一.问题 习惯了linux命令,在windows上使用cmd没有这些命令时很不习惯. 二.解决办法 2.1 找到这些命令对应的windows命令 ls,对应于windows的dir pwd,对应于wi ...

  2. macaca使用中问题解决方法整理

    报告老板:很多同学在搭建macaca的环境时候,出现了各种问题,尤其是使用windows的同学,更是复杂且费劲的要命,我这里针对一些遇到的坑,按照从头的搭建开始说起,如下 基本的搭建条件要满足基础环境 ...

  3. ARM-GPIO

    操作GPIO有三种方法: 调用库函数读取IO的输入电平:uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef*GPIOx,uint16_t GPIO_pin): 操作寄 ...

  4. GlusterFS分布式存储学习笔记

    分布式文件系统 分布式文件系统(Distributed File System)是指文件系统管理的物理存储资源并不直接与本地节点相连,而是分布于计算网络中的一个或者多个节点的计算机上.目前意义上的分布 ...

  5. better-scroll的参数和方法

    格式:let obj = new BScroll(object,{[option1,],.,.}); 注意,如果在某一个组件内创建了一个BScroll的实例,在组件生命周期结束前要注意调用destro ...

  6. 《Linux内核设计与实现》读书笔记——第四章

    标签(空格分隔): 20135321余佳源 第四章 进程调度 调度程序负责决定将哪个进程投入运行,何时运行以及运行多长时间,进程调度程序可看做在可运行态进程之间分配有限的处理器时间资源的内核子系统. ...

  7. Linux实践一:问题及解决

    安装ubuntu出现的问题 : 打开镜像.iso文件,v-box好像是不识别这种格式的,它识别的好像是.vdi等格式,所以要用vm虚拟机打开镜像安装 打开镜像,按照步骤安装后,安装很久后,出现问题.初 ...

  8. 同步手绘板——android端下笔后颜色变化

    实现效果 : 在设计之初我们以为是改变笔线条的粗细来实现类似效果,后来通过找其他相关软件比对发现是不改变线条的粗细,通过改变透明度实现下笔后颜色的渐变,虽然已实现,但渐变效果很一般,不流畅,算法还待优 ...

  9. 第三个Sprint ------第八天

    四则运算APP开发基本完成! PC端运行结果截图 移动端(华为手机)测试截图 总结:通过这次课程设计,我体会到团队协作的重要性,也体会到了理论联系实际的意义.做一件事,要坚持不懈,不能半途而废!

  10. 2017BUAA软工个人项目之数独生成与求解

    1.项目GitHub地址:https://github.com/ZiJiaW/Soduko (由于一开始把sudoku看成了soduko,于是名字建错了,读起来可能有点奇怪…) 2.项目PSP表格如下 ...