NOIP2016 天天爱跑步
题目描述
小c同学认为跑步非常有趣,于是决定制作一款叫做《天天爱跑步》的游戏。《天天爱跑步》是一个养成类游戏,需要玩家每天按时上线,完成打卡任务。
这个游戏的地图可以看作一一棵包含 nnn 个结点和 n−1n-1n−1 条边的树, 每条边连接两个结点,且任意两个结点存在一条路径互相可达。树上结点编号为从111 到nnn 的连续正整数。
现在有mmm 个玩家,第iii 个玩家的起点为 SiS_iSi ,终点为 TiT_iTi 。每天打卡任务开始时,所有玩家在第000 秒同时从自己的起点出发, 以每秒跑一条边的速度, 不间断地沿着最短路径向着自己的终点跑去, 跑到终点后该玩家就算完成了打卡任务。 (由于地图是一棵树, 所以每个人的路径是唯一的)
小C想知道游戏的活跃度, 所以在每个结点上都放置了一个观察员。 在结点jjj 的观察员会选择在第WjW_jWj 秒观察玩家, 一个玩家能被这个观察员观察到当且仅当该玩家在第WjW_jWj 秒也理到达了结点 jjj 。 小C想知道每个观察员会观察到多少人?
注意: 我们认为一个玩家到达自己的终点后该玩家就会结束游戏, 他不能等待一 段时间后再被观察员观察到。 即对于把结点jjj 作为终点的玩家: 若他在第WjW_jWj 秒前到达终点,则在结点jjj 的观察员不能观察到该玩家;若他正好在第WjW_jWj 秒到达终点,则在结点jjj 的观察员可以观察到这个玩家。
输入输出格式
输入格式:
第一行有两个整数nnn 和mmm 。其中nnn 代表树的结点数量, 同时也是观察员的数量, mmm 代表玩家的数量。
接下来 n−1n- 1n−1 行每行两个整数uuu 和 vvv ,表示结点 uuu 到结点 vvv 有一条边。
接下来一行 nnn 个整数,其中第jjj 个整数为WjW_jWj , 表示结点jjj 出现观察员的时间。
接下来 mmm 行,每行两个整数SiS_iSi ,和TiT_iTi ,表示一个玩家的起点和终点。
对于所有的数据,保证1≤Si,Ti≤n,0≤Wj≤n1\leq S_i,T_i\leq n, 0\leq W_j\leq n1≤Si,Ti≤n,0≤Wj≤n 。
输出格式:
输出1行 nnn 个整数,第jjj 个整数表示结点jjj 的观察员可以观察到多少人。
输入输出样例
说明
【样例1说明】
对于1号点,Wi=0W_i=0Wi=0 ,故只有起点为1号点的玩家才会被观察到,所以玩家1和玩家2被观察到,共有2人被观察到。
对于2号点,没有玩家在第2秒时在此结点,共0人被观察到。
对于3号点,没有玩家在第5秒时在此结点,共0人被观察到。
对于4号点,玩家1被观察到,共1人被观察到。
对于5号点,玩家1被观察到,共1人被观察到。
对于6号点,玩家3被观察到,共1人被观察到。
【子任务】
每个测试点的数据规模及特点如下表所示。 提示: 数据范围的个位上的数字可以帮助判断是哪一种数据类型。
【提示】
如果你的程序需要用到较大的栈空问 (这通常意味着需要较深层数的递归), 请务必仔细阅读选手日录下的文本当rumung:/stact.p″, 以了解在最终评测时栈空问的限制与在当前工作环境下调整栈空问限制的方法。
在最终评测时,调用栈占用的空间大小不会有单独的限制,但在我们的工作
环境中默认会有 8 MB 的限制。 这可能会引起函数调用层数较多时, 程序发生
栈溢出崩溃。
我们可以使用一些方法修改调用栈的大小限制。 例如, 在终端中输入下列命
令 ulimit -s 1048576
此命令的意义是,将调用栈的大小限制修改为 1 GB。
例如,在选手目录建立如下 sample.cpp 或 sample.pas
将上述源代码编译为可执行文件 sample 后,可以在终端中运行如下命令运
行该程序
./sample
如果在没有使用命令“ ulimit -s 1048576”的情况下运行该程序, sample
会因为栈溢出而崩溃; 如果使用了上述命令后运行该程序,该程序则不会崩溃。
特别地, 当你打开多个终端时, 它们并不会共享该命令, 你需要分别对它们
运行该命令。
请注意, 调用栈占用的空间会计入总空间占用中, 和程序其他部分占用的内
存共同受到内存限制。
25分暴力模拟做法
1 //2018年2月16日21:22:53 2 #include <iostream> 3 #include <cstdio> 4 using namespace std; 5 6 const int N = 300001; 7 const int M = 300001; 8 9 int n, m; 10 11 struct Edge{ 12 int to, nxt; 13 }E[M]; 14 15 int fir[N], edge_Num, w[N], s[N], t[N], sig[N]; 16 void addEdge(int x, int y){ 17 E[++edge_Num].to = y; 18 E[edge_Num].nxt = fir[x]; 19 fir[x] = edge_Num; 20 } 21 22 int lca[N]; 23 int fa[N], top[N], deep[N], siz[N], son[N], val[N]; 24 25 void dfs1(int x){ 26 deep[x] = deep[fa[x]] + 1; 27 siz[x] = 1; 28 for(int i=fir[x]; i; i=E[i].nxt){ 29 int to = E[i].to; 30 if(fa[x] != to){ 31 fa[to] = x; 32 dfs1(to); 33 siz[x] += siz[to]; 34 if(siz[son[x]] < siz[to]) son[x] = to; 35 } 36 } 37 } 38 39 void dfs2(int x){ 40 if(x == son[fa[x]]) top[x] = top[fa[x]]; 41 else top[x] = x; 42 for(int i=fir[x]; i; i=E[i].nxt) 43 if(fa[E[i].to] == x) 44 dfs2(E[i].to); 45 } 46 int query(int x, int y){ 47 for(; top[x] != top[y]; deep[top[x]]>deep[top[y]]?x=fa[top[x]]:y=fa[top[y]]); 48 return deep[x]<deep[y]?x:y; 49 } 50 int tim; 51 void dfsup(int x, int ii){ 52 if(x == s[ii]){ 53 if(w[x] == tim) sig[x]++; 54 dfsup(fa[x], ii); 55 }else{ 56 tim++; 57 if(w[x] == tim) sig[x]++; 58 if(x == lca[ii]) return; 59 dfsup(fa[x], ii); 60 } 61 } 62 63 void dfsdown(int x, int ii){ 64 if(x == lca[ii]){ 65 tim--; 66 if(w[x] == tim) sig[x]++; 67 return; 68 } 69 if(x == t[ii]){ 70 tim = deep[t[ii]]-deep[lca[ii]] + tim; 71 if(w[x] == tim) sig[x]++; 72 dfsdown(fa[x], ii); 73 }else{ 74 tim--; 75 if(w[x] == tim) sig[x]++; 76 dfsdown(fa[x], ii); 77 } 78 } 79 80 int main(){ 81 scanf("%d%d", &n, &m); 82 for(int i=1;i<n;i++){ 83 int x, y; 84 scanf("%d%d", &x, &y); 85 addEdge(x, y); 86 addEdge(y, x); 87 } 88 for(int i=1;i<=n;i++) 89 scanf("%d", &w[i]); 90 dfs1(1); 91 dfs2(1); 92 for(int i=1;i<=m;i++){ 93 scanf("%d%d", &s[i], &t[i]); 94 lca[i] = query(s[i], t[i]); 95 tim = 0; 96 if(s[i] != lca[i]){ 97 dfsup(s[i], i); 98 if(t[i] == lca[i]); 99 else dfsdown(t[i], i); 100 }else if(s[i] == t[i]){ 101 if(w[s[i]] == 0) sig[s[i]]++; 102 }else{ 103 dfsdown(t[i], i); 104 } 105 } 106 //.... 107 for(int i=1;i<=n;i++) 108 printf("%d ", sig[i]); 109 110 return 0; 111 }
未完待续, 等着将来填坑