个人思路:
- 类似”雨天的尾巴”,在dfs的过程中合并数据即可。可以注意到W范围较大,且区间具有可合并性(非最大/小值等操作).
- 因此,可利用vector维护每个点上”玩家”的增加/减少情况,再在dfs的过程中利用全局数组合并即可.
- 具体地说,对于每个玩家,分成两段分别考虑,即S->LCA和LCA->T。可以发现,在第一种情况下满足W[x]-d[x]=d[s];在第二种情况下满足W[x]-d[x]=d[s]-2*d[lca(s,t)].
- 代入树上差分的基本过程中可以发现:在第一种情况下,利用区间合并使得lca(s,t)与s之间的点可以利用该情况的数据,第二种情况同理。当然,也可以直接用两个局部变量cnt1,cnt2分别维护W[x]-d[x],W[x]+d[x],并在一次dfs中求得结果.
#include<cstdio>
#include<iostream>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=1000010,MAXM=1000010;
struct Edge{
int from,to,nxt;
}e[MAXM];
int head[MAXN],edgeCnt=1;
void addEdge(int u,int v){
e[++edgeCnt].from=u;
e[edgeCnt].to=v;
e[edgeCnt].nxt=head[u];
head[u]=edgeCnt;
}
int dep[MAXN],f[MAXN][21];
void dfs_Lca(int x){
dep[x]=dep[f[x][0]]+1;
for(int i=1;i<=20;i++){
f[x][i]=f[f[x][i-1]][i-1];
}
for(int i=head[x];i;i=e[i].nxt){
int v=e[i].to;
if(!dep[v]){
f[v][0]=x;
dfs_Lca(v);
}
}
}
int lca(int a,int b){
if(dep[a]>dep[b])swap(a,b);
for(int i=20;i>=0;i--){
if(dep[b]-(1<<i)>=dep[a])b=f[b][i];
}
if(a==b)return a;
for(int i=20;i>=0;i--)
if(f[a][i]!=f[b][i])
a=f[a][i],b=f[b][i];
return f[a][0];
}
int w[MAXN];
struct player{
int s,t;
}players[MAXN];
struct item{
int pos,value;
};
vector<item> vecs_First[MAXN];
int c[MAXN],ans[MAXN];
void dfs_Solve_First(int x){
int cnt=c[w[x]+dep[x]];
for(int i=head[x];i;i=e[i].nxt){
int v=e[i].to;
if(v!=f[x][0]){
dfs_Solve_First(v);
}
}
while(!vecs_First[x].empty()){
item nowItem=vecs_First[x].back();vecs_First[x].pop_back();
int nowPos=nowItem.pos,nowValue=nowItem.value;
c[nowPos]+=nowValue;
}
ans[x]+=c[w[x]+dep[x]]-cnt;
}
void init(){
memset(c,0,sizeof(c));
}
vector<item> vecs_Second[MAXN];
void dfs_Solve_Second(int x){
int cnt=c[w[x]-dep[x]];
for(int i=head[x];i;i=e[i].nxt){
int v=e[i].to;
if(v!=f[x][0]){
dfs_Solve_Second(v);
}
}
while(!vecs_Second[x].empty()){
item nowItem=vecs_Second[x].back();vecs_Second[x].pop_back();
int nowPos=nowItem.pos,nowValue=nowItem.value;
c[nowPos]+=nowValue;
}
ans[x]+=c[w[x]-dep[x]]-cnt;
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n-1;i++){
int u,v;
scanf("%d%d",&u,&v);
addEdge(u,v);
addEdge(v,u);
}
f[1][0]=0;
dfs_Lca(1);
for(int i=1;i<=n;i++){
scanf("%d",&w[i]);
}
for(int i=1;i<=m;i++){
scanf("%d%d",&players[i].s,&players[i].t);
vecs_First[players[i].s].
push_back(item{dep[players[i].s],1});
vecs_First[f[lca(players[i].s,players[i].t)][0]].
push_back(item{dep[players[i].s],-1});
vecs_Second[players[i].t].
push_back(item{dep[players[i].s]-2*dep[lca(players[i].s,players[i].t)],1});
vecs_Second[lca(players[i].s,players[i].t)].
push_back(item{dep[players[i].s]-2*dep[lca(players[i].s,players[i].t)],-1});
}
dfs_Solve_First(1);
init();
dfs_Solve_Second(1);
for(int i=1;i<=n-1;i++){
cout<<ans[i]<<" ";
}
printf("%d\n",ans[n]);
return 0;
}