【NOIP2016提高组复赛day2】天天爱跑步
2016-12-02 19:09
351 查看
题目
小 C 同学认为跑步非常有趣,于是决定制作一款叫做《天天爱跑步》的游戏。 《天天爱跑步》是一个养成类游戏,需要玩家每天按时上线,完成打卡任务。 这个游戏的地图可以看作一棵包含 n 个结点和 n − 1 条边的树,每条边连接两个结点,且任意两个结点存在一条路径互相可达。树上结点编号为从 1 到 n 的连续正整数。 现在有 m 个玩家,第 i 个玩家的起点为 Si ,终点为 Ti 。每天打卡任务开始时,所 有玩家在第 0 秒同时从自己的起点出发,以每秒跑一条边的速度,不间断地沿着 最短 路径向着自己的终点跑去,跑到终点后该玩家就算完成了打卡任务。(由于地图是一棵树,所以每个人的路径是唯一的)小 C 想知道游戏的活跃度,所以在每个结点上都放置了一个观察员。在结点 j 的 观 察员会选择在第 Wj 秒观察玩家,一个玩家能被这个观察员观察到当且仅当该玩家 在第 Wj 秒也正好到达了结点 j 。小 C 想知道每个观察员会观察到多少人?
注意:我们认为一个玩家到达自己的终点后该玩家就会结束游戏,他不能等待一 段时间后再被观察员观察到。即对于把结点 j 作为终点的玩家:若他在第 Wj 秒前到达 终点,则在结点 j 的观察员不能观察到该玩家;若他正好在第 Wj 秒到达终点,则在结 点 j 的观察员可以观察到这个玩家。
分析
假设有一条路径(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 ,next ,last ,to ,deep1 ,n,m,w ,tot,ans ,a [2],g [20],sum,mxd,t[N*4],t1[N*4]; int next1 ,last1 ,to1 ,tot1; int next2 ,last2 ,to2 ,tot2; int next3 ,last3 ,to3 ,tot3; int next4 ,last4 ,to4 ,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提高组复赛】天天爱跑步
- NOIP 2011 提高组 复赛 day2 factor 计算系数
- NOIP 2013 提高组 复赛 day2 block 积木大赛
- NOIP 2016 提高组 Day2 组合数问题
- NOIP 2016 提高组 复赛 Day2T1==洛谷2822 组合数问题
- {题解}[jzoj4907]【NOIP2016提高组复赛】蚯蚓
- 蚯蚓 NOIP2016 提高组 Day2 T2
- 2016NOIP提高组复赛山东赛区满分选手代码片段汇编
- NOIP2013复赛提高组day2(A:积木大赛 B:花匠 C:华容道)
- 【Luogu P2282】【JZOJ 4906】【NOIP2016提高组复赛】组合数问题 题解
- NOIP2016 提高组 DAY2 解题思路
- 【NOIP2016提高组复赛】玩具谜题
- 【NOIP 2016 提高组】天天爱跑步
- NOIP 2011 提高组 复赛 day2 qc 聪明的质监员
- 【NOIP2016提高组复赛】愤怒的小鸟
- NOIP 2015 提高组 复赛 day2 stone 跳石头
- 【NOIP2016提高A组模拟8.19】(雅礼联考day2)树上路径
- NOIP2011复赛提高组day2(A:计算系数 B:聪明的质监员 C:观光公交)
- NOIP2016提高组复赛解题报告
- 【NOIP2016提高组复赛】换教室