[NOIP2016]天天爱跑步
题目描述
小c同学认为跑步非常有趣,于是决定制作一款叫做《天天爱跑步》的游戏。天天爱跑步是一个养成类游戏,需要 玩家每天按时上线,完成打卡任务。
这个游戏的地图可以看作一一棵包含 N个结点和N-1 条边的树, 每条边连接两个结点,且任意两个结点存在一条路径互相可达。树上结点编号为从1到N的连续正整数。
现在有个玩家,第个玩家的 起点为Si ,终点为Ti 。每天打卡任务开始时,所有玩家在第0秒同时从自己的起点出发, 以每秒跑一条边的速度, 不间断地沿着最短路径向着自己的终点跑去, 跑到终点后该玩家就算完成了打卡任务。 (由于地图是一棵树, 所以 每个人的路径是唯一的)
小C想知道游戏的活跃度, 所以在每个结点上都放置了一个观察员。 在结点的观察员会选 择在第Wj秒观察玩家, 一个玩家能被这个观察员观察到当且仅当该玩家在第Wj秒也正好到达了结点J 。 小C想知道 每个观察员会观察到多少人?
注意: 我们认为一个玩家到达自己的终点后该玩家就会结束游戏, 他不能等待一 段时 间后再被观察员观察到。 即对于把结点J作为终点的玩家: 若他在第Wj秒重到达终点,则在结点J的观察员不能观察 到该玩家;若他正好在第Wj秒到达终点,则在结点的观察员可以观察到这个玩家。
。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
题解开始:
一眼看出将每人的运动过程分成两部分(应该没啥异议),然后发现两个性质:
1.向树根跑的人,t+dep不变;
2.向叶子跑的人,dep-t不变;
然后用两个桶存上面两个值,dfs就行。
代码:
#include<cstdio> #include<algorithm> using namespace std; #define N 300005 int n,m,hed[N],cnt; inline int rd() { int f=1,c=0;char ch = getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){c=(c<<3)+(c<<1)+ch-'0';ch=getchar();} return f*c; } struct EDge { int to; int nxt; }e[2*N]; void ae(int f,int t) { e[++cnt].to=t; e[cnt].nxt=hed[f]; hed[f]=cnt; } int tp[N],fa[N],dep[N],son[N],siz[N]; void dfs0(int u) { siz[u]=1; for(int j=hed[u];j;j=e[j].nxt) { int to = e[j].to; if(to==fa[u])continue; fa[to]=u; dep[to]=dep[u]+1; dfs0(to); if(siz[to]>siz[son[u]]) { son[u]=to; } siz[u]+=siz[to]; } } void dfs1(int u,int tpp) { tp[u]=tpp; if(!son[u])return ; dfs1(son[u],tpp); for(int j=hed[u];j;j=e[j].nxt) { int to = e[j].to; if(to==fa[u]||to==son[u])continue; dfs1(to,to); } } int get_lca(int a,int b) { while(tp[a]!=tp[b]) { if(dep[tp[a]]<dep[tp[b]])swap(a,b); a=fa[tp[a]]; } return dep[a]>dep[b]?b:a; } int w[N],ans[N]; int dfsx[N][2],cnt1[2];//0 dep+w 1 dep-w struct Node { int v,delta,nxt; }d1[N<<1][2]; void aN(int x,int tip,int v,int delta) { d1[++cnt1[tip]][tip].v=v; d1[cnt1[tip]][tip].delta=delta; d1[cnt1[tip]][tip].nxt=dfsx[x][tip]; dfsx[x][tip]=cnt1[tip]; } int T[N<<1][2]; void dfs(int u) { int tmp = T[dep[u]+w[u]+N][0]+T[dep[u]-w[u]+N][1]; for(int j=hed[u];j;j=e[j].nxt) { int to = e[j].to; if(to==fa[u])continue; dfs(to); } for(int tp = 0;tp<=1;tp++) { for(int j=dfsx[u][tp];j;j=d1[j][tp].nxt) { T[d1[j][tp].v+N][tp]+=d1[j][tp].delta; } } ans[u]+=(T[dep[u]+w[u]+N][0]+T[dep[u]-w[u]+N][1])-tmp; } int main() { n=rd(),m=rd(); for(int f,t,i=1;i<n;i++) { f=rd(),t=rd(); ae(f,t); ae(t,f); } dfs0(1); dfs1(1,1); for(int i=1;i<=n;i++) { w[i]=rd(); } for(int f,t,i=1;i<=m;i++) { f=rd(),t=rd(); int LCA = get_lca(f,t); if(dep[LCA]+w[LCA]==dep[f])ans[LCA]--; aN(f,0,dep[f],1); aN(fa[LCA],0,dep[f],-1); aN(t,1,2*dep[LCA]-dep[f],1); aN(fa[LCA],1,2*dep[LCA]-dep[f],-1); } dfs(1); for(int i=1;i<=n;i++) { printf("%d ",ans[i]); } printf("\n"); return 0; }