如果没有时间的限制,这题就是对每个点 i i i,求经过 i i i的路径数,用树上差分解决即可:
枚举路径 x → y { x\to y\{ x→y{
a [ x ] + = 1 ; a [ y ] + = 1 ; a[x]+=1;a[y]+=1; a[x]+=1;a[y]+=1;
a [ l c a ( x , y ) ] − = 1 ; a [ f a [ l c a ( x , y ) ] ] − = 2 ; a[lca(x,y)]-=1;a[fa[lca(x,y)]]-=2; a[lca(x,y)]−=1;a[fa[lca(x,y)]]−=2;
} \} }
枚举点 i { i\{ i{
经过 i i i的路径数 = 以 i i i为根的子树中 a a a的和
} \} }
(用树状数组实现)
考虑加上时间限制怎么做:
我们把每条路径 x → y x\to y x→y拆成上行段和下行段。
-
若点 i i i在 x → y x\to y x→y的上行段上,
i i i点的观察员看到从 x x x出发跑到 y y y的玩家,当且仅当
d e p [ x ] − d e p [ i ] = w [ i ] dep[x]-dep[i]=w[i] dep[x]−dep[i]=w[i]即 d e p [ i ] + w [ i ] = d e p [ x ] dep[i]+w[i]=dep[x] dep[i]+w[i]=dep[x] -
若点 i i i在 x → y x\to y x→y的下行段上,
i i i点的观察员看到从 x x x出发跑到 y y y的玩家,当且仅当
d e p [ x ] + d e p [ y ] − 2 d e p [ l c a ( x , y ) ] − ( d e p [ y ] − d e p [ i ] ) = w [ i ] dep[x]+dep[y]-2dep[lca(x,y)]-(dep[y]-dep[i])=w[i] dep[x]+dep[y]−2dep[lca(x,y)]−(dep[y]−dep[i])=w[i]
即 d e p [ i ] − w [ i ] = 2 d e p [ l c a ( x , y ) ] − d e p [ x ] dep[i]-w[i]=2dep[lca(x,y)]-dep[x] dep[i]−w[i]=2dep[lca(x,y)]−dep[x]
对于路径 x → y x\to y x→y,我们将其拆成 上行段 p : x → l c a ( x , y ) p:x\to lca(x,y) p:x→lca(x,y)在 x x x方向上的儿子,下行段 q : l c a ( x , y ) → y q:lca(x,y)\to y q:lca(x,y)→y,并记 v [ p ] = d e p [ x ] v[p]=dep[x] v[p]=dep[x], v [ q ] = 2 d e p [ l c a ( x , y ) ] − d e p [ x ] v[q]=2dep[lca(x,y)]-dep[x] v[q]=2dep[lca(x,y)]−dep[x]
对于点 i i i,我们记 v p [ i ] = d e p [ i ] + w [ i ] v_p[i]=dep[i]+w[i] vp[i]=dep[i]+w[i], v q [ i ] = d e p [ i ] − w [ i ] v_q[i]=dep[i]-w[i] vq[i]=dep[i]−w[i]
那么 i i i点的观察员看到的玩家数 = ∑ \sum ∑经过 i i i且满足 v [ p ] = v p [ i ] v[p]=v_p[i] v[p]=vp[i]的上行段 p p p的数量 + ∑ \sum ∑经过 i i i且满足 v [ q ] = v q [ i ] v[q]=v_q[i] v[q]=vq[i]的下行段 q q q的数量
先把点按 v p [ i ] v_p[i] vp[i]排序,把上行段按 v [ p ] v[p] v[p]排序,按树上差分的套路计算上行段的贡献。
再把点按 v q [ i ] v_q[i] vq[i]排序,把下行段按 v [ q ] v[q] v[q]排序,按树上差分的套路计算下行段的贡献。
如此即可得到最终答案。
#include<iostream>
#include<cstdio>
#include<stack>
#include<algorithm>
using namespace std;
const int N=1e6+10;
struct Edge{
int v,nxt;
}edge[N<<1];
int n,m,w[N],cnt,head[N],ans[N];
int ind,dfn[N],siz[N],dep[N],fa[N][20];
struct Query{
int nd,x;
friend bool operator < (Query a,Query b){
return a.x<b.x;
}
}a[N<<1];
struct Data{
int d,u,x;
friend bool operator < (Data a,Data b){
return a.x<b.x;
}
}b[2][N];
int tot[2];
stack<Data> s;
void addedge(int u,int v){
edge[++cnt].v=v;edge[cnt].nxt=head[u];head[u]=cnt;
}
void dfs(int u){
dfn[u]=++ind;
siz[u]=1;
for(int i=1;i<=19;i++)
fa[u][i]=fa[fa[u][i-1]][i-1];
for(int i=head[u];i;i=edge[i].nxt){
int v=edge[i].v;
if(v==fa[u][0]) continue;
fa[v][0]=u;
dep[v]=dep[u]+1;
dfs(v);
siz[u]+=siz[v];
}
}
int LCA(int u,int v){
if(dep[u]<dep[v]) swap(u,v);
int diff=dep[u]-dep[v];
for(int i=19;i>=0;i--){
if(diff&(1<<i)) u=fa[u][i];
}
if(u==v) return u;
for(int i=19;i>=0;i--){
if(fa[u][i]!=fa[v][i]){
u=fa[u][i];
v=fa[v][i];
}
}
return fa[u][0];
}
int c[N];
int lowbit(int x){
return x&(-x);}
void add(int x,int v){
if(!x) return;
for(int i=x;i<=n;i+=lowbit(i)) c[i]+=v;
}
int sum(int x){
int res=0;
for(int i=x;i;i-=lowbit(i)) res+=c[i];
return res;
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<n;i++){
int u,v;
scanf("%d%d",&u,&v);
addedge(u,v);
addedge(v,u);
}
dep[1]=1;dfs(1);
for(int i=1;i<=n;i++){
scanf("%d",&w[i]);
a[i]=(Query){
i,dep[i]+w[i]};
a[i+n]=(Query){
i,dep[i]-w[i]};
}
sort(a+1,a+n+1);
sort(a+n+1,a+2*n+1);
for(int i=1;i<=m;i++){
int s,t,lca;
scanf("%d%d",&s,&t);
lca=LCA(s,t);
if(s==lca){
b[1][++tot[1]]=(Data){
t,s,dep[s]};
}
else if(t==lca){
b[0][++tot[0]]=(Data){
s,t,dep[s]};
}
else{
int son=s;
for(int i=19;i>=0;i--){
if(dep[fa[son][i]]>dep[lca]) son=fa[son][i];
}
b[0][++tot[0]]=(Data){
s,son,dep[s]};
b[1][++tot[1]]=(Data){
t,lca,2*dep[lca]-dep[s]};
}
}
sort(b[0]+1,b[0]+tot[0]+1);
sort(b[1]+1,b[1]+tot[1]+1);
int p=1;
for(int i=1;i<=n;i++){
if(a[i].x!=a[i-1].x){
while(!s.empty()){
Data tmp=s.top();s.pop();
add(dfn[fa[tmp.u][0]],1);
add(dfn[tmp.d],-1);
}
}
for(;p<=tot[0]&&b[0][p].x<=a[i].x;p++){
if(a[i].x!=a[i-1].x&&b[0][p].x==a[i].x){
Data tmp=b[0][p];
add(dfn[fa[tmp.u][0]],-1);
add(dfn[tmp.d],1);
s.push(tmp);
}
}
ans[a[i].nd]+=sum(dfn[a[i].nd]+siz[a[i].nd]-1)-sum(dfn[a[i].nd]-1);
}
while(!s.empty()){
Data tmp=s.top();s.pop();
add(dfn[fa[tmp.u][0]],1);
add(dfn[tmp.d],-1);
}
p=1;
for(int i=n+1;i<=2*n;i++){
if(a[i].x!=a[i-1].x){
while(!s.empty()){
Data tmp=s.top();s.pop();
add(dfn[fa[tmp.u][0]],1);
add(dfn[tmp.d],-1);
}
}
for(;p<=tot[1]&&b[1][p].x<=a[i].x;p++){
if(a[i].x!=a[i-1].x&&b[1][p].x==a[i].x){
Data tmp=b[1][p];
add(dfn[fa[tmp.u][0]],-1);
add(dfn[tmp.d],1);
s.push(tmp);
}
}
ans[a[i].nd]+=sum(dfn[a[i].nd]+siz[a[i].nd]-1)-sum(dfn[a[i].nd]-1);
}
for(int i=1;i<=n;i++)
printf("%d ",ans[i]);
return 0;
}