题目:BZOJ4719.
题目大意:给定一棵
n
n
n个点的树和树上每个节点的
w
i
w_i
wi,现在给出
m
m
m对
s
i
s_i
si和
t
i
t_i
ti,表示从
s
i
s_i
si到
t
i
t_i
ti会有一个人沿树上的路径走过,并且这个人每秒移动到下一个点.现在每个人都在时刻
0
0
0走出,询问每一个点
i
i
i,请你输出第
w
i
w_i
wi时刻有多少人会在点
i
i
i.
1
≤
n
,
m
≤
3
∗
1
0
5
1\leq n,m\leq 3*10^5
1≤n,m≤3∗105.
考虑先把每个人对应的有向路径拆成两部分,一部分是从起点到LCA,另一部分是从LCA到终点.
接下来我们只讨论第一部分的统计,第二部分类似.
首先我们把所有人时间定义为他的深度,这样子一个人会在第一部分被点 i i i统计当且仅当他会走过点 i i i且他的时间 = w i + d e p [ i ] =w_i+dep[i] =wi+dep[i].
那么我们就可以考虑树上差分.我们在树上每个点开个二元组vector,然后对于第 i i i个人,在他起点的vector里增加一个二元组表示增加这个人的贡献,在他LCA增加一个二元组表示减少这个人的贡献.
现在我们dfs一遍整棵树,考虑需要统计的东西.显然答案为一个点 k k k为根的子树中的所有点vector中的时间为 w [ k ] + d e p [ k ] w[k]+dep[k] w[k]+dep[k]的人的贡献和.
为了维护这个东西,我们考虑在dfs的过程中维护一个桶记录对应时间的贡献和,当进入一个点的时候先把这个点的答案减去当前桶中对应时间的贡献,再给桶中加入这个点vector的贡献,在退出前再加上当前桶中对应时间的贡献和就好了.
时间复杂度 O ( n + m log n ) O(n+m\log n) O(n+mlogn).
注意处理LCA只能算一次的细节.
代码如下:
##include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=300000;
int n,m;
struct side{
int y,next;
}e[N*2+9];
int lin[N+9],cs;
void Ins(int x,int y){e[++cs].y=y;e[cs].next=lin[x];lin[x]=cs;}
void Ins2(int x,int y){Ins(x,y);Ins(y,x);}
int w[N+9];
int st[N+9],td[N+9];
struct node{
int fa,son,dep,siz,top;
}d[N+9];
void Dfs_ord1(int k,int fa){
d[k].fa=fa;
d[k].dep=d[fa].dep+1;
d[k].siz=1;
for (int i=lin[k];i;i=e[i].next)
if (e[i].y^fa){
Dfs_ord1(e[i].y,k);
d[k].siz+=d[e[i].y].siz;
if (d[e[i].y].siz>d[d[k].son].siz) d[k].son=e[i].y;
}
}
void Dfs_ord2(int k,int top){
d[k].top=top;
if (d[k].son) Dfs_ord2(d[k].son,top);
for (int i=lin[k];i;i=e[i].next)
if (e[i].y^d[k].fa&&e[i].y^d[k].son) Dfs_ord2(e[i].y,e[i].y);
}
int Query_lca(int x,int y){
for (;d[x].top^d[y].top;x=d[d[x].top].fa)
if (d[d[x].top].dep<d[d[y].top].dep) swap(x,y);
return d[x].dep<d[y].dep?x:y;
}
vector<int>a[2][N+9],v[2][N+9];
int Insert(int id,int k,int t,int x){a[id][k].push_back(t);v[id][k].push_back(x);}
int cnt[2][N*2+9],ans[N+9];
void Dfs_ans(int k){
if (w[k]<=n) ans[k]-=cnt[0][w[k]+d[k].dep]+cnt[1][w[k]-d[k].dep+n];
int siz=a[0][k].size();
for (int i=0;i<siz;++i) cnt[0][a[0][k][i]]+=v[0][k][i];
siz=a[1][k].size();
for (int i=0;i<siz;++i) cnt[1][a[1][k][i]]+=v[1][k][i];
for (int i=lin[k];i;i=e[i].next)
if (e[i].y^d[k].fa) Dfs_ans(e[i].y);
if (w[k]<=n) ans[k]+=cnt[0][w[k]+d[k].dep]+cnt[1][w[k]-d[k].dep+n];
}
void Get_ans(){
for (int i=1;i<=m;++i){
int lca=Query_lca(st[i],td[i]),t0=d[st[i]].dep,t1=d[st[i]].dep-2*d[lca].dep+n;
Insert(0,st[i],t0,1);
Insert(0,d[lca].fa,t0,-1);
Insert(1,td[i],t1,1);
Insert(1,lca,t1,-1);
}
Dfs_ans(1);
}
Abigail into(){
scanf("%d%d",&n,&m);
for (int i=1;i<n;++i){
int x,y;
scanf("%d%d",&x,&y);
Ins2(x,y);
}
for (int i=1;i<=n;++i)
scanf("%d",&w[i]);
for (int i=1;i<=m;++i)
scanf("%d%d",&st[i],&td[i]);
}
Abigail work(){
Dfs_ord1(1,0);
Dfs_ord2(1,1);
Get_ans();
}
Abigail outo(){
for (int i=1;i<=n;++i)
printf("%d ",ans[i]);
puts("");
}
int main(){
into();
work();
outo();
return 0;
}