这题被我 3 min 胡出来了的样子。
考虑,m 对点 $(s_i,t_i)$ 去贡献点 j。
考虑贡献式: $dep_s+dep_x-2dep_{lca(s,x)}=w_x$。
如果 $xin [s,lca(s,t)]$,那么 $dep_s-dep_x=w_x,dep_s=dep_x+w_x$,用 $dep_s_$ 去贡献即可。具体我不太会,用了个比较蠢的分块维护桶。
$ xin[lca(s,t),t]$,那么 $dep_s+dep_x-2*dep_{lca(s,x)}=w_x$,此时 $lca(s,x)=lca(s,t)$,$dep_s-2*dep{lca(s,t)}=w_x-dep_x$,考虑用这东西去贡献下就好。由于 $w_x-dep_x in[-n,n]$,要值域平移。
注意下空间。时复 $O(nsqrt{n}log n)$。
#include <cstdio> #include <algorithm> #include <iostream> #include <cstring> #include <vector> #include <cmath> #include <queue> #include <map> #define ll long long using namespace std; int rd() { int f=1,sum=0; char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();} return sum*f; } ll lrd() { ll f=1,sum=0; char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)) {sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();} return sum*f; } /* dis=w_x dep_A+dep_x-2*dep_lca=w_x dep_A-2*dep_lca=w_x-dep_x 分块,块内维护个桶 */ const int N=(int)(3e5+2),M=410; struct edge { int nex,to; }e[N<<1]; int dep[N],fa[N],top[N],son[N],sz[N],id[N],rk[N],tot; int head[N],cnt,w[N],ans[N],n,m; void add_edge(int x,int y) { e[++cnt].nex=head[x]; e[cnt].to=y; head[x]=cnt; } void dfs1(int x,int ff) { dep[x]=dep[ff]+1; fa[x]=ff; sz[x]=1; for(int i=head[x];i;i=e[i].nex) { int y=e[i].to; if(y==ff) continue; dfs1(y,x); sz[x]+=sz[y]; if(sz[y]>sz[son[x]]) son[x]=y; } } void dfs2(int x,int tp) { top[x]=tp; id[x]=++tot; rk[tot]=x; if(son[x]) dfs2(son[x],tp); for(int i=head[x];i;i=e[i].nex) { int y=e[i].to; if(y==fa[x]||y==son[x]) continue; dfs2(y,y); } } #define K (int)(3e5) int L[M],R[M],bid[N],bl,cnt1[M][N<<1],cnt2[M][N<<1]; void init() { bl=sqrt(1.0*n*1.8); for(int i=1;i<=n;i++) bid[i]=(i-1)/bl+1; for(int i=1;i<=bid[n];i++) L[i]=(i-1)*bl+1,R[i]=i*bl; R[bid[n]]=n; } void upt1(int l,int r,int pos) { if(bid[l]==bid[r]) { for(int i=l;i<=r;i++) if(w[rk[i]]+dep[rk[i]]==pos) ++ans[i]; } else { for(int i=l;i<=R[bid[l]];i++) if(w[rk[i]]+dep[rk[i]]==pos) ++ans[i]; for(int i=L[bid[r]];i<=r;i++) if(w[rk[i]]+dep[rk[i]]==pos) ++ans[i]; for(int i=bid[l]+1;i<bid[r];i++) ++cnt1[i][pos+K]; } } void upt2(int l,int r,int pos) { if(bid[l]==bid[r]) { for(int i=l;i<=r;i++) if(w[rk[i]]-dep[rk[i]]==pos) ++ans[i]; } else { for(int i=l;i<=R[bid[l]];i++) if(w[rk[i]]-dep[rk[i]]==pos) ++ans[i]; for(int i=L[bid[r]];i<=r;i++) if(w[rk[i]]-dep[rk[i]]==pos) ++ans[i]; for(int i=bid[l]+1;i<bid[r];i++) ++cnt2[i][pos+K]; } } int query(int x) { //cout<<w[x]-dep[x]<<endl; return ans[x]+cnt1[bid[x]][w[rk[x]]+dep[rk[x]]+K]+cnt2[bid[x]][w[rk[x]]-dep[rk[x]]+K]; } int LCA(int x,int y) { while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) swap(x,y); x=fa[top[x]]; } return dep[x]<dep[y]?x:y; } // dep_A-dep_x+dis=w_x w_x+dep_x=dep_A+dis // dep_A-dep_x=w_x w_x+dep_x=dep_A // all_dis-(dep_A-dep_x)=all_dis-dep_A+dep_x=w_x // w_x-dep_x=all_dis-dep_A /* dep_x+dep_y-2*dep_lca=w_y dep_A-dep_x=w_x 1. dep_x=w_y+dep_y 2. dep_x-2*dep_d=w_y-dep_y */ void update1(int x,int y) { int A=x; while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) swap(x,y); upt1(id[top[x]],id[x],dep[A]); x=fa[top[x]]; } if(id[x]>id[y]) swap(x,y); upt1(id[x],id[y],dep[A]); } void update2(int depd,int u,int x,int y) { int A=u; while(top[x]!=top[y]) { if(dep[top[x]]<dep[top[y]]) swap(x,y); upt2(id[top[x]],id[x],dep[A]-2*depd); x=fa[top[x]]; } if(id[x]>id[y]) swap(x,y); upt2(id[x],id[y],dep[A]-2*depd); } void pr(int x) { if(x<0) {putchar('-');x=-x;} if(x>9) pr(x/10); putchar(x%10+'0'); } int main() { int x,y; n=rd(); m=rd(); for(int i=1;i<n;i++) { x=rd(); y=rd(); add_edge(x,y); add_edge(y,x); } for(int i=1;i<=n;i++) w[i]=rd(); dfs1(1,0); dfs2(1,0); init(); while(m--) { x=rd(); y=rd(); int d=LCA(x,y); update1(x,d); update2(dep[d],x,y,d); if(dep[x]-dep[d]==w[d]) --ans[id[d]]; // cout<<dep[x]+dep[y]-2*dep[d]<<": "; // puts(""); } for(int i=1;i<=n;i++) pr(query(id[i])),putchar(' '); return 0; }