[NOIP2016]天天爱跑步(树上差分+线段树合并)
将每个人跑步的路径拆分成x->lca,lca->y两条路径分别考虑:
对于在点i的观察点,这个人(s->t)能被观察到的充要条件为:
1.直向上的路径:w[i]=dep[s]-dep[i],移项得w[i]+dep[i]=dep[s]
2.直向下的路径:w[i]=dep[s]-dep[lca]+dep[i]-dep[lca],移项得w[i]-dep[i]=dep[s]-2*dep[lca]。
问题转化为,对每个点i,统计它的子树中有多少个点x满足dep[x]=w[i]+dep[i]或dep[x]-2*dep[lca]=w[i]-dep[i],这是经典的线段树合并问题。
注意到并不是子树中所有满足条件的点都能被统计,因为有的点还没到观察点就往下跑了(lca深度大于当前观察点),差分解决。
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #define lson ls[x],L,mid 6 #define rson rs[x],mid+1,R 7 #define rep(i,l,r) for (int i=l; i<=r; i++) 8 #define For(i,x) for (int i=h[x],k; i; i=nxt[i]) 9 typedef long long ll; 10 using namespace std; 11 12 const int N=300010,M=10000010; 13 int n,m,u,v,cnt,s,t,w[N],d[N],ans[N],fa[N][20],h[N],nxt[N<<1],to[N<<1]; 14 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; } 15 16 struct T{ 17 int nd,v[M],ls[M],rs[M],rt[N]; 18 void ins(int &x,int L,int R,int pos,int k){ 19 if (!x) x=++nd; 20 if (L==R){ v[x]+=k; return; } 21 int mid=(L+R)>>1; 22 if (pos<=mid) ins(lson,pos,k); else ins(rson,pos,k); 23 } 24 25 int merge(int x,int y,int L,int R){ 26 if (!x || !y) return x+y; 27 if (L==R) { v[x]+=v[y]; return x; } 28 int mid=(L+R)>>1; 29 ls[x]=merge(ls[x],ls[y],L,mid); 30 rs[x]=merge(rs[x],rs[y],mid+1,R); 31 return x; 32 } 33 34 int que(int x,int L,int R,int pos){ 35 if (!x) return 0; 36 if (L==R) return v[x]; 37 int mid=(L+R)>>1; 38 if (pos<=mid) return que(lson,pos); else return que(rson,pos); 39 } 40 }T1,T2; 41 42 void dfs(int x){ 43 rep(i,1,19) fa[x][i]=fa[fa[x][i-1]][i-1]; 44 For(i,x) if ((k=to[i])!=fa[x][0]) fa[k][0]=x,d[k]=d[x]+1,dfs(k); 45 } 46 47 void dfs2(int x){ 48 For(i,x) if ((k=to[i])!=fa[x][0]){ 49 dfs2(k); 50 T1.rt[x]=T1.merge(T1.rt[x],T1.rt[k],0,n); 51 T2.rt[x]=T2.merge(T2.rt[x],T2.rt[k],0,2*n); 52 } 53 ans[x]+=(w[x]+d[x]>=0 && w[x]+d[x]<=n) ? T1.que(T1.rt[x],0,n,w[x]+d[x]) : 0; 54 ans[x]+=(w[x]-d[x]>=-n && w[x]-d[x]<=n) ? T2.que(T2.rt[x],0,2*n,w[x]-d[x]+n) : 0; 55 } 56 57 int Lca(int x,int y){ 58 if (d[x]<d[y]) swap(x,y); 59 int t=d[x]-d[y]; 60 for (int i=19; ~i; i--) if (t&(1<<i)) x=fa[x][i]; 61 if (x==y) return x; 62 for (int i=19; ~i; i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; 63 return fa[x][0]; 64 } 65 66 int main(){ 67 freopen("running.in","r",stdin); 68 freopen("running.out","w",stdout); 69 scanf("%d%d",&n,&m); 70 rep(i,2,n) scanf("%d%d",&u,&v),add(u,v),add(v,u); 71 rep(i,1,n) scanf("%d",&w[i]); 72 dfs(1); 73 rep(i,1,m){ 74 scanf("%d%d",&s,&t); int lca=Lca(s,t); 75 T1.ins(T1.rt[s],0,n,d[s],1); T1.ins(T1.rt[fa[lca][0]],0,n,d[s],-1); 76 T2.ins(T2.rt[t],0,2*n,d[s]-2*d[lca]+n,1); 77 T2.ins(T2.rt[fa[lca][0]],0,2*n,d[s]-2*d[lca]+n,-1); 78 if (d[s]-d[lca]==w[lca]) ans[lca]--; 79 } 80 dfs2(1); 81 rep(i,1,n) printf("%d ",ans[i]); puts(""); 82 return 0; 83 }