/*把每个玩家的路径拆成一条到LCA的路径和从LCA到终点的路径~ 然后,使用树上差分统计答案即可~
那么,树上差分是什么? 差分的具体思想是,当某区间内某元素对答案有贡献,就在区间起点打一个+1
标记代表多出了一个对答案有贡献的元素,在终点打一个-1标记代表一个对答案有贡献的元素在该位置
结束了它的使命。 于是,统计答案就变成了维护扫到当前位置为止的标记个数,直接累加就是答案~ 首先
对从下到上的路径观察~ 然后就会发现:所有对某点上的观察员i有贡献的点只可能是以i点往下w[i]层深
度的任一后代为起点的玩家~ 然后我们就可以维护一个标记数组,每个位置分别表示当前共访问了多少个深
度为当前位置下标的点。 直接dfs,先对目标深度,也就是对当前观察员i有贡献的深度为dep[i]+w[i]的
标记,记录其当前的值。 然后递归搜索所有子树,每搜到一个点便把以当前点为起点的所有路径加入当前点深
度的标记中,代表这些点开始产生贡献,并把以当前点为LCA的所有路径从从该路径起点所在深度中减去,代
表这些点停止产生贡献。 当回溯到当前点,统计搜索完所有子树后dep[i]+w[i]处标记的新值,并减去记
录下的旧的值,作为当前节点的答案~ 这样搜一遍,正向的便被统计完了~ 从LCA到终点的方法同理,只是
在dep[i]-w[i]时可能有负数出现,加上30000的偏移量即可~ */
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<vector>
using namespace std;
const int MAXN = 302333;
#define pb push_back
struct Player{ int s,t,lca,len; }a[MAXN];
int to[MAXN<<1],nxt[MAXN<<1],head[MAXN<<1],n,m,w[MAXN],deep,tot;
vector<int> upper[MAXN],down1[MAXN],down2[MAXN];
inline void read(int &x){
x=0; int f=1; char c=getchar();
while(c>'9'||c<'0'){ if(c=='-') f=-1; c=getchar(); }
while(c>='0'&&c<='9'){ x=x*10+c-'0'; c=getchar(); } x*=f;
}
inline void Add_(int u,int v){ to[++tot]=v,nxt[tot]=head[u],head[u]=tot; }
inline void Add_Edge(int u,int v){ Add_(u,v),Add_(v,u); }
int top[MAXN],dep[MAXN],siz[MAXN],son[MAXN],fa[MAXN];
int pos[MAXN],ans[MAXN],delta[MAXN<<1];
void DFS1(int u,int father,int deepth){
fa[u]=father,dep[u]=deepth,siz[u]=1,son[u]=0;
deep=max(deep,deepth);
for(int i=head[u];i;i=nxt[i]){
int v=to[i];
if(v==father) continue;
DFS1(v,u,deepth+1);
siz[u]+=siz[v];
if(!son[u]||siz[v]>siz[son[u]]) son[u]=v;
}
}
void DFS2(int u,int Top){
top[u]=Top;
if(son[u]) DFS2(son[u],Top);
for(int i=head[u];i;i=nxt[i]){
int v=to[i];
if(v!=fa[u]&&v!=son[u]) DFS2(v,v);
}
}
inline int Get_Lca(int u,int v){
while(top[u]!=top[v]){
if(dep[top[u]]<dep[top[v]]) swap(u,v);
u=fa[top[u]];
}
if(dep[u]>dep[v]) swap(u,v);
return u;
}
void DFS3(int u){
int now=dep[u]+w[u],last=delta[now];
for(int i=head[u];i;i=nxt[i])
if(to[i]!=fa[u]) DFS3(to[i]);
delta[dep[u]]+=pos[u];
if(now<=deep) ans[u]=delta[now]-last;
for(int i=0;i<upper[u].size();++i)
delta[dep[upper[u][i]]]--;
}
#define W30 300000
void DFS4(int u){
int now=dep[u]-w[u]+W30,last=delta[now];
for(int i=head[u];i;i=nxt[i])
if(to[i]!=fa[u]) DFS4(to[i]);
for(int i=0;i<down1[u].size();++i)
++delta[down1[u][i]+W30];
ans[u]+=delta[now]-last;
for(int i=0;i<down2[u].size();++i)
--delta[down2[u][i]+W30];
}
int main(){
read(n),read(m);
for(int i=1,u,v;i<n;++i)
read(u),read(v),Add_Edge(u,v);
DFS1(1,1,1);
top[1]=1;
DFS2(1,1);
for(int i=1;i<=n;++i) read(w[i]);
for(int i=1;i<=m;++i){
read(a[i].s),read(a[i].t);
a[i].lca=Get_Lca(a[i].s,a[i].t);
a[i].len=dep[a[i].s]+dep[a[i].t]-(dep[a[i].lca]<<1);
pos[a[i].s]++;
upper[a[i].lca].pb(a[i].s);
}
DFS3(1);
for(int i=1;i<=m;++i){
down1[a[i].t].pb(dep[a[i].t]-a[i].len);
down2[a[i].lca].pb(dep[a[i].t]-a[i].len);
}
memset(delta,0,sizeof delta );
DFS4(1);
for(int i=1;i<=m;++i)
if(dep[a[i].s]==dep[a[i].lca]+w[a[i].lca])
--ans[a[i].lca];
printf("%d",ans[1]);
for(int i=2;i<=n;++i) printf(" %d",ans[i]);
return 0;
}
洛谷 P1600 天天爱跑步
最新推荐文章于 2021-08-29 00:58:59 发布