【NOIP2016提高組復賽day2】天天愛跑步
題目
小 C 同學認為跑步非常有趣,於是決定制作一款叫做《天天愛跑步》的遊戲。 《天天愛跑步》是一個養成類遊戲,需要玩家每天按時上線,完成打卡任務。 這個遊戲的地圖可以看作一棵包含 n 個結點和 n ? 1 條邊的樹,每條邊連接兩個結點,且任意兩個結點存在一條路徑互相可達。樹上結點編號為從 1 到 n 的連續正整數。 現在有 m 個玩家,第 i 個玩家的起點為 Si ,終點為 Ti 。每天打卡任務開始時,所 有玩家在第 0 秒同時從自己的起點出發,以每秒跑一條邊的速度,不間斷地沿著 最短 路徑向著自己的終點跑去,跑到終點後該玩家就算完成了打卡任務。(由於地圖是一棵樹,所以每個人的路徑是唯一的)
小 C 想知道遊戲的活躍度,所以在每個結點上都放置了一個觀察員。在結點 j 的 觀 察員會選擇在第 Wj 秒觀察玩家,一個玩家能被這個觀察員觀察到當且僅當該玩家 在第 Wj 秒也正好到達了結點 j 。小 C 想知道每個觀察員會觀察到多少人?
分析
假設有一條路徑(x->y),最近公共祖先lca,
考慮i這個點是否能觀察到這個玩家,
才成兩條路徑,分兩種情況,
一、(x->lca)
如果要使i可以觀察到,
i一定在(x->lca)上
那麽deep[i]+w[i]=deep[x]。
建一個桶,
在x入棧時將deep[x]加入到桶中,
在lca退棧時,將deep[x]踢掉。
二、(lca的某個兒子且為j的祖先->y)
如果要使i可以觀察到,
i一定在(lca的某個兒子且為j的祖先->y)上
那麽deep[i]-w[i]=deep[y]-t(t=deep[x]+deep[y]-deep[lca]*2)。
再建一個桶,
同樣
在y入棧時將deep[y]-t加入到同中,
在lca的某個兒子且為j的祖先退棧時,將deep[y]-t踢掉。
因為會算重,所以將做完以i為根的子樹後的值-i進棧時的值就是i的答案。
#include <algorithm> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <iostream> using namespace std; const int N=700005; int deep[N],next[N],last[N],to[N],deep1[N],n,m,w[N],tot,ans[N],a[N][2],g[N][20],sum,mxd,t[N*4],t1[N*4]; int next1[N],last1[N],to1[N],tot1; int next2[N],last2[N],to2[N],tot2; int next3[N],last3[N],to3[N],tot3; int next4[N],last4[N],to4[N],tot4; int bj(int x,int y){next[++tot]=last[x];last[x]=tot;to[tot]=y;} int bj1(int x,int y){next1[++tot1]=last1[x];last1[x]=tot1;to1[tot1]=y;} int bj2(int x,int y){next2[++tot2]=last2[x];last2[x]=tot2;to2[tot2]=y;} int bj3(int x,int y){next3[++tot3]=last3[x];last3[x]=tot3;to3[tot3]=y;} int bj4(int x,int y){next4[++tot4]=last4[x];last4[x]=tot4;to4[tot4]=y;} int dg(int x) { for(int i=last[x];i;i=next[i]) { int j=to[i]; if(j!=g[x][0]) { g[j][0]=x; deep[j]=deep[x]+1; dg(j); } } } int lca(int x,int y) { if(deep[x]>deep[y]) { int o=x; x=y; y=o; } for(int j=log2(n);j>=0;j--) { if(deep[g[y][j]]>=deep[x]) y=g[y][j]; } for(int j=log2(n);j>=0;j--) { if(g[y][j]!=g[x][j]) y=g[y][j],x=g[x][j]; } if(x!=y) y=g[y][0],x=g[x][0]; return x; } int dg1(int x) { int xx=t[deep[x]+w[x]]+t1[deep[x]-w[x]+N]; for(int i=last1[x];i;i=next1[i]) t[to1[i]]++; for(int i=last3[x];i;i=next3[i]) t1[to3[i]+N]++; for(int i=last[x];i;i=next[i]) if(to[i]!=g[x][0]) dg1(to[i]); ans[x]=t[deep[x]+w[x]]+t1[deep[x]-w[x]+N]-xx; for(int i=last2[x];i;i=next2[i]) t[to2[i]]--; for(int i=last4[x];i;i=next4[i]) t1[to4[i]+N]--; } int main() { freopen("running.in","r",stdin); freopen("running.out","w",stdout); scanf("%d%d",&n,&m); for(int i=1;i<=n-1;i++) { int x,y; scanf("%d%d",&x,&y); bj(x,y); bj(y,x); } for(int i=1;i<=n;i++) scanf("%d",&w[i]); deep[1]=1; dg(1); for(int j=1;j<=log2(n);j++) for(int i=1;i<=n;i++) g[i][j]=g[g[i][j-1]][j-1]; for(int i=1;i<=m;i++) { int x,y; scanf("%d%d",&x,&y); int top=lca(x,y),t=deep[x]+deep[y]-2*deep[top]; if(top==x) { bj3(y,deep[y]-t); bj4(x,deep[y]-t); } else if(top==y) { bj1(x,deep[x]); bj2(y,deep[x]); } else { bj1(x,deep[x]); bj2(top,deep[x]); bj3(y,deep[y]-t); for(int j=last[top];j;j=next[j]) { if(to[j]!=g[top][0] && lca(to[j],y)==to[j]) { bj4(to[j],deep[y]-t); break; } } } } dg1(1); for(int i=1;i<=n;i++) printf("%d ",ans[i]); return 0; }
【NOIP2016提高組復賽day2】天天愛跑步