【天天愛跑步】
阿新 • • 發佈:2019-01-01
智商不夠資料結構來湊
常規操作就是將樹上的一條路徑\((s,t)\)拆分成\((s,lca)\)和\((lca,t)\)來看
首先考慮一下上行路徑
顯然對於點\(x\)來說,只有\(dep[s]=dep[x]+a[x]\)且\(lca\)在\(x\)子樹外面
好像非常難算的樣子,我們考慮減掉\(lca\)在子樹內部的情況
於是我們先不考慮\(lca\)在\(x\)子樹外面這一限制條件,我們直接求出所有的的\(dep[x]=dep[x]+a[x]\),也就是求在\(dep[x]+a[x]\)這一深度上有幾個起點
主席樹上樹可以隨便做
之後減掉\(lca\)在子樹內部的情況,於是我們可以將起點的深度作為權值,減掉子樹內部的所有權值為\(dep[x]+a[x]\)
之後是下行路徑
顯然這個時候需要滿足的條件是\(L-a[x]+dep[x]-1=dep[t]\),其中\(L\)表示路徑長度
同時還得滿足\(lca\)在子樹外面
我們可以把\(dep[t]-L\)作為權值,之後還是子樹查詢就好了
所以一共需要四個主席樹
同時還有幾個比較坑的地方
主席樹的值域開大一些,大概\(2*n\)就足夠了
儘管我們要減掉\(lca\)在子樹內部的情況,但是\(lca\)恰好在\(x\)時是可以的,於是還要加回來
lca如果算了兩次那麼就需要特判一下
程式碼
#include<iostream> #include<cstring> #include<cstdio> #include<vector> #define re register #define maxn 300000 #define max(a,b) ((a)>(b)?(a):(b)) struct E { int v,nxt; }e[maxn<<1]; int n,m,num,maxdep,tot; int fa[maxn],top[maxn],deep[maxn],son[maxn],sum[maxn],to[maxn],_to[maxn]; int a[maxn],head[maxn],v1[maxn]; int ans[maxn]; std::vector<int> v2[maxn],v3[maxn],v4[maxn]; inline int read() { char c=getchar(); int x=0; while(c<'0'||c>'9') c=getchar(); while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar(); return x; } inline void add_edge(int x,int y) { e[++num].v=y; e[num].nxt=head[x]; head[x]=num; } void dfs1(int x) { sum[x]=1; int maxx=-1; for(re int i=head[x];i;i=e[i].nxt) if(!deep[e[i].v]) { deep[e[i].v]=deep[x]+1; maxdep=max(maxdep,deep[e[i].v]); fa[e[i].v]=x; dfs1(e[i].v); sum[x]+=sum[e[i].v]; if(sum[e[i].v]>maxx) son[x]=e[i].v,maxx=sum[e[i].v]; } } void dfs2(int x,int topf) { top[x]=topf; to[x]=++tot; _to[tot]=x; if(!son[x]) return; dfs2(son[x],topf); for(re int i=head[x];i;i=e[i].nxt) if(deep[e[i].v]>deep[x]&&son[x]!=e[i].v) dfs2(e[i].v,e[i].v); } inline int LCA(int x,int y) { while(top[x]!=top[y]) { if(deep[top[x]]<deep[top[y]]) std::swap(x,y); x=fa[top[x]]; } if(deep[x]>deep[y]) return y; return x; } struct Segment_Tree { int l[maxn*29],r[maxn*29],d[maxn*29]; int rt[maxn]; int cnt; int build(int x,int y) { int root=++cnt; if(x==y) return root; int mid=x+y>>1; l[root]=build(x,mid),r[root]=build(mid+1,y); return root; } int change(int pre,int x,int y,int pos,int val) { int root=++cnt; d[root]=d[pre]+val; if(x==y) return root; l[root]=l[pre],r[root]=r[pre]; int mid=x+y>>1; if(pos<=mid) l[root]=change(l[pre],x,mid,pos,val); else r[root]=change(r[pre],mid+1,y,pos,val); return root; } int query(int p,int x,int y,int pos) { if(x==y) return d[p]; int mid=x+y>>1; if(pos<=mid) return query(l[p],x,mid,pos); return query(r[p],mid+1,y,pos); } }up,_up,down,_down; int main() { n=read(),m=read(); int x,y; for(re int i=1;i<n;i++) x=read(),y=read(),add_edge(x,y),add_edge(y,x); deep[1]=1; dfs1(1),dfs2(1,1); for(re int i=1;i<=n;i++) a[i]=read(); int s,t; for(re int i=1;i<=m;i++) { s=read(),t=read(); int lca=LCA(s,t); int L=deep[s]+deep[t]-2*deep[lca]+1; if(deep[s]-deep[lca]==a[lca]) ans[lca]--; v1[s]++; v2[lca].push_back(deep[s]); v3[t].push_back(deep[t]-L+n); v4[lca].push_back(deep[t]-L+n); } up.rt[0]=up.build(1,n*2); _up.rt[0]=_up.build(1,n*2); down.rt[0]=down.build(0,n*2); _down.rt[0]=_down.build(0,n*2); for(re int i=1;i<=n;i++) { up.rt[i]=up.change(up.rt[i-1],1,n*2,deep[_to[i]],v1[_to[i]]); int pre=_up.rt[i-1]; for(re int j=0;j<v2[_to[i]].size();j++) pre=_up.change(pre,1,n*2,v2[_to[i]][j],1); _up.rt[i]=pre; pre=down.rt[i-1]; for(re int j=0;j<v3[_to[i]].size();j++) pre=down.change(pre,0,n*2,v3[_to[i]][j],1); down.rt[i]=pre; pre=_down.rt[i-1]; for(re int j=0;j<v4[_to[i]].size();j++) pre=_down.change(pre,0,n*2,v4[_to[i]][j],1); _down.rt[i]=pre; } for(re int i=1;i<=n;i++) { int x=to[i],y=to[i]+sum[i]-1; ans[i]+=up.query(up.rt[y],1,n*2,deep[i]+a[i])-up.query(up.rt[x-1],1,n*2,deep[i]+a[i]); ans[i]-=_up.query(_up.rt[y],1,n*2,deep[i]+a[i])-_up.query(_up.rt[x-1],1,n*2,deep[i]+a[i]); ans[i]+=_up.query(_up.rt[x],1,n*2,deep[i]+a[i])-_up.query(_up.rt[x-1],1,n*2,deep[i]+a[i]); ans[i]+=down.query(down.rt[y],0,n*2,deep[i]-a[i]-1+n)-down.query(down.rt[x-1],0,n*2,deep[i]-a[i]-1+n); ans[i]-=_down.query(_down.rt[y],0,n*2,deep[i]-a[i]-1+n)-_down.query(_down.rt[x-1],0,n*2,deep[i]-a[i]-1+n); ans[i]+=_down.query(_down.rt[x],0,n*2,deep[i]-a[i]-1+n)-_down.query(_down.rt[x-1],0,n*2,deep[i]-a[i]-1+n); } for(re int i=1;i<=n;i++) printf("%d ",ans[i]); return 0; }