bzoj4719[Noip2016]天天爱跑步

Description

小c同学认为跑步非常有趣,于是决定制作一款叫做《天天爱跑步》的游戏。?天天爱跑步?是一个养成类游戏,需要玩家每天按时上线,完成打卡任务。这个游戏的地图可以看作一一棵包含 N个结点和N-1 条边的树, 每条边连接两个结点,且任意两个结点存在一条路径互相可达。树上结点编号为从1到N的连续正整数。现在有个玩家,第个玩家的起点为Si ,终点为Ti  。每天打卡任务开始时,所有玩家在第0秒同时从自己的起点出发, 以每秒跑一条边的速度,不间断地沿着最短路径向着自己的终点跑去, 跑到终点后该玩家就算完成了打卡任务。 (由于地图是一棵树, 所以每个人的路径是唯一的)小C想知道游戏的活跃度, 所以在每个结点上都放置了一个观察员。 在结点的观察员会选择在第Wj秒观察玩家, 一个玩家能被这个观察员观察到当且仅当该玩家在第Wj秒也理到达了结点J  。 小C想知道每个观察员会观察到多少人?注意: 我们认为一个玩家到达自己的终点后该玩家就会结束游戏, 他不能等待一 段时间后再被观察员观察到。 即对于把结点J作为终点的玩家: 若他在第Wj秒重到达终点,则在结点J的观察员不能观察到该玩家;若他正好在第Wj秒到达终点,则在结点的观察员可以观察到这个玩家。

Input

第一行有两个整数N和M 。其中N代表树的结点数量, 同时也是观察员的数量, M代表玩家的数量。

接下来n-1 行每行两个整数U和V ,表示结点U 到结点V 有一条边。

接下来一行N 个整数,其中第个整数为Wj , 表示结点出现观察员的时间。

接下来 M行,每行两个整数Si和Ti,表示一个玩家的起点和终点。

对于所有的数据,保证 。

1<=Si,Ti<=N,0<=Wj<=N

Output

输出1行N 个整数,第个整数表示结点的观察员可以观察到多少人。

Sample Input

6 3

2 3

1 2

1 4

4 5

4 6

0 2 5 1 2 3

1 5

1 3

2 6

Sample Output

1 2 1 0 1

HINT

对于1号点,Wi=0,故只有起点为1号点的玩家才会被观察到,所以玩家1和玩家2被观察到,共有2人被观察到。

对于2号点,没有玩家在第2秒时在此结点,共0人被观察到。

对于3号点,没有玩家在第5秒时在此结点,共0人被观察到。

对于4号点,玩家1被观察到,共1人被观察到。

对于5号点,玩家1被观察到,共1人被观察到。

对于6号点,玩家3被观察到,共1人被观察到。

输入样例#2:

5 3
1 2
2 3
2 4
1 5
0 1 0 3 0
3 1
1 4
5 5 

输出样例#2:

1 2 1 0 1 

【子任务】

每个测试点的数据规模及特点如下表所示。 提示: 数据范围的个位上的数字可以帮助判断是哪一种数据类型。

【提示】

如果你的程序需要用到较大的栈空问 (这通常意味着需要较深层数的递归), 请务必仔细阅读选手日录下的文本当rumung:/stact.p″, 以了解在最终评测时栈空问的限制与在当前工作环境下调整栈空问限制的方法。

在最终评测时,调用栈占用的空间大小不会有单独的限制,但在我们的工作

环境中默认会有 8 MB 的限制。 这可能会引起函数调用层数较多时, 程序发生

栈溢出崩溃。

我们可以使用一些方法修改调用栈的大小限制。 例如, 在终端中输入下列命

令 ulimit -s 1048576

此命令的意义是,将调用栈的大小限制修改为 1 GB。

例如,在选手目录建立如下 sample.cpp 或 sample.pas

将上述源代码编译为可执行文件 sample 后,可以在终端中运行如下命令运

行该程序

./sample

如果在没有使用命令“ ulimit -s 1048576”的情况下运行该程序, sample

会因为栈溢出而崩溃; 如果使用了上述命令后运行该程序,该程序则不会崩溃。

特别地, 当你打开多个终端时, 它们并不会共享该命令, 你需要分别对它们

运行该命令。

请注意, 调用栈占用的空间会计入总空间占用中, 和程序其他部分占用的内

存共同受到内存限制。

考场上我做了暴力和s=1的特殊情况。

本蒟蒻表示看了半天题解才懂。

正解:

对于每一条路径,拆成一条向上的链和一条向下的链,在向上的链中,需满足d[s]-d[i]=w[i],即d[s]=d[i]+w[i],问题转化为,在树上将s到lca的路径标上d[s],最后ans[i]就等于在i点上等于d[i]+w[i]的标记的个数。但直接标记路径上所有的点太慢,我们可以在s点打上+1的标记,lca点打上-1的标记,然后dfs做求子树和,为避免将其它子树的和计入ans,只要记录进入这个点时的cnt[d[i]+w[i]],访问完这个点后用新的cnt[d[i]+w[i]]减去进来的就可以了。一些实现上的细节见代码。

蒟蒻表示不会tarjanLCA所以写了个倍增lca。

  1 program running(input,output);
  2 type
  3   etype=record
  4      t,next:longint;
  5   end;
  6   pointer=^nodetype;
  7   nodetype=record
  8      x:longint;
  9      next:pointer;
 10   end;
 11 var
 12   e:array[0..600060]of etype;
 13   u,v,d,c,lca,q,w,ans:array[0..300030]of longint;
 14   vis:array[0..300030]of boolean;
 15   cnt:array[-600060..600060]of longint;
 16   father:array[0..300030,0..20]of longint;
 17   a,b:array[0..300030]of pointer;
 18   p:pointer;
 19   n,m,i,j,k,x,y,tot,h,t:longint;
 20 procedure add(x,y:longint);
 21 begin
 22    inc(tot);e[tot].t:=y;e[tot].next:=c[x];c[x]:=tot;
 23 end;
 24 function query(x,y:longint):longint;
 25 begin
 26    if d[x]<d[y] then begin t:=x;x:=y;y:=t; end;
 27    j:=k;while d[x]>d[y] do begin if d[father[x,j]]>=d[y] then x:=father[x,j];dec(j); end;
 28    if x=y then exit(x);
 29    j:=k;while j>=0 do begin if father[x,j]<>father[y,j] then begin x:=father[x,j];y:=father[y,j]; end;dec(j); end;
 30    exit(father[x,0]);
 31 end;
 32 procedure prepare;
 33 begin
 34    fillchar(d,sizeof(d),0);
 35    h:=0;t:=1;q[1]:=1;d[1]:=1;father[1,0]:=0;
 36    while h<t do
 37       begin
 38          inc(h);
 39          i:=c[q[h]];
 40          while i<>0 do
 41             begin
 42                if d[e[i].t]=0 then
 43                   begin
 44                      d[e[i].t]:=d[q[h]]+1;father[e[i].t,0]:=q[h];
 45                      inc(t);q[t]:=e[i].t;
 46                   end;
 47                i:=e[i].next;
 48             end;
 49       end;
 50    k:=1;
 51    for i:=1 to 20 do begin if k+k>=d[q[n]] then break;k:=k+k; end;
 52    k:=i;
 53    for j:=1 to k do
 54       for i:=1 to n do father[i,j]:=father[father[i,j-1],j-1];
 55    for i:=1 to m do lca[i]:=query(u[i],v[i]);
 56 end;
 57 procedure ins(x,y:longint);
 58 begin
 59    new(p);p^.x:=y;p^.next:=a[x];a[x]:=p;
 60 end;
 61 procedure del(x,y:longint);
 62 begin
 63    new(p);p^.x:=y;p^.next:=b[x];b[x]:=p;
 64 end;
 65 procedure dfs1(k:longint);
 66 var
 67   i,j:longint;
 68 begin
 69    vis[k]:=true;
 70    j:=cnt[w[k]+d[k]];
 71    i:=c[k];
 72    while i<>0 do
 73       begin
 74          if not vis[e[i].t] then dfs1(e[i].t);
 75          i:=e[i].next;
 76       end;
 77    p:=a[k];while p<>nil do begin inc(cnt[p^.x]);p:=p^.next; end;
 78    ans[k]:=cnt[w[k]+d[k]]-j;
 79    p:=b[k];while p<>nil do begin dec(cnt[p^.x]);p:=p^.next; end;
 80 end;
 81 procedure dfs2(k:longint);
 82 var
 83   i,j:longint;
 84 begin
 85    vis[k]:=true;
 86    j:=cnt[w[k]-d[k]];
 87    i:=c[k];
 88    while i<>0 do
 89       begin
 90          if not vis[e[i].t] then dfs2(e[i].t);
 91          i:=e[i].next;
 92       end;
 93    p:=a[k];while p<>nil do begin inc(cnt[p^.x]);p:=p^.next; end;
 94    p:=b[k];while p<>nil do begin dec(cnt[p^.x]);p:=p^.next; end;
 95    ans[k]:=ans[k]+cnt[w[k]-d[k]]-j;
 96 end;
 97 begin
 98    assign(input,‘running.in‘);assign(output,‘running.out‘);reset(input);rewrite(output);
 99    readln(n,m);
100    tot:=0;fillchar(c,sizeof(c),0);
101    for i:=2 to n do begin readln(x,y);add(x,y);add(y,x); end;
102    for i:=1 to n do read(w[i]);
103    for i:=1 to m do readln(u[i],v[i]);
104    prepare;
105    for i:=1 to n do begin a[i]:=nil;b[i]:=nil; end;
106    for i:=1 to m do begin ins(u[i],d[u[i]]);del(lca[i],d[u[i]]); end;
107    fillchar(cnt,sizeof(cnt),0);
108    fillchar(vis,sizeof(vis),false);
109    dfs1(1);
110    for i:=1 to n do begin a[i]:=nil;b[i]:=nil; end;
111    for i:=1 to m do begin t:=d[u[i]]-d[lca[i]]-d[lca[i]];ins(v[i],t);del(lca[i],t); end;
112    fillchar(cnt,sizeof(cnt),0);
113    fillchar(vis,sizeof(vis),false);
114    dfs2(1);
115    write(ans[1]);for i:=2 to n do write(‘ ‘,ans[i]);
116    close(input);close(output);
117 end.
时间: 2024-10-03 23:00:34

bzoj4719[Noip2016]天天爱跑步的相关文章

bzoj4719: [Noip2016]天天爱跑步 树上差分

Description 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.?天天爱跑步?是一个养成类游戏,需要 玩家每天按时上线,完成打卡任务.这个游戏的地图可以看作一一棵包含 N个结点和N-1 条边的树, 每条边连接两 个结点,且任意两个结点存在一条路径互相可达.树上结点编号为从1到N的连续正整数.现在有个玩家,第个玩家的 起点为Si ,终点为Ti .每天打卡任务开始时,所有玩家在第0秒同时从自己的起点出发, 以每秒跑一条边的速度, 不间断地沿着最短路径向着自己的终点跑去,

NOIP2016天天爱跑步

2557. [NOIP2016]天天爱跑步 时间限制:2 s   内存限制:512 MB [题目描述] 小C同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一棵包含n个结点和n-1条边的树,每条边连接两个结点,且任意两个结点存在一条路径互相可达.树上结点编号为从1到n的连续正整数. 现在有m个玩家,第i个玩家的起点为Si,终点为Ti.每天打卡任务开始时,所有玩家在第0秒同时从

bzoj 4719: [Noip2016]天天爱跑步

Description 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.?天天爱跑步?是一个养成类游戏,需要 玩家每天按时上线,完成打卡任务.这个游戏的地图可以看作一一棵包含 N个结点和N-1 条边的树, 每条边连接两 个结点,且任意两个结点存在一条路径互相可达.树上结点编号为从1到N的连续正整数.现在有个玩家,第个玩家的 起点为Si ,终点为Ti  .每天打卡任务开始时,所有玩家在第0秒同时从自己的起点出发, 以每秒跑一条边的速度, 不间断地沿着最短路径向着自己的终点跑去

LCA+线段树 NOIP2016 天天爱跑步

天天爱跑步 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.?天天爱跑步?是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 nnn个结点和 n?1n-1n?1条边的树, 每条边连接两个结点,且任意两个结点存在一条路径互相可达.树上结点编号为从111到nnn的连续正整数. 现在有mmm个玩家,第iii个玩家的起点为 SiS_iS?i??,终点为 TiT_iT?i?? .每天打卡任务开始时,所有玩家在第000秒同时从自己的起点出

noip2016 天天爱跑步

分析:这道题真心烦啊,是我做过noip真题中难度最高的一道了,到今天为止才把noip2016的坑给填满.暴力的话前60分应该是可以拿满的,后40分还是很有难度的. 定义:每个人的起点.终点:s,t;深度:deep[i];观察员出现时间:w[i]; 首先,树上两个点的最短路径肯定要经过LCA,那么对于路径x ---> y我们可以分成两部分:1.x ---> lca. 2.lca ---> y.先分析第一段路上的观察员i,显然s到i的距离等于w[i]才行,这段路是从x向上跳的,所以可以得到式

NOIP2016 天天爱跑步 正解

暴力移步 http://www.cnblogs.com/TheRoadToTheGold/p/6673430.html 首先解决本题应用的知识点: dfs序——将求子树的信息(树形)转化为求一段连续区间信息(线形) 线段树——求区间信息 树上差分——统计答案 lca——拆分路径 树链剖分——求lca 另deep[]表示节点的深度,watch[]表示观察者的出现时间,s表示玩家起点,t表示终点 固定节点的观察者出现的时间固定,说明对这个观察者有贡献的点是有限且固定的 只有满足  观察者出现时间=玩

BZOJ 4719 [Noip2016]天天爱跑步 ——树链剖分

一直以为自己当时是TLE了,但是再看发现居然WA? 然后把数组扩大一倍,就A掉了.QaQ 没什么好说的.一段路径分成两段考虑,上升的一段深度+时间是定值,下降的一段深度-时间是定值,然后打标记统计即可. 发现大概是统计数组因为深度+时间太大炸掉了. 现在想想,当时没有对拍,真是后怕. #include <cstdio> #include <vector> #include <cstring> #include <iostream> #include <

BZOJ 4719--天天爱跑步(LCA&amp;差分)

4719: [Noip2016]天天爱跑步 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 1464  Solved: 490[Submit][Status][Discuss] Description 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.?天天爱跑步?是一个养成类游戏,需要 玩家每天按时上线,完成打卡任务.这个游戏的地图可以看作一一棵包含 N个结点和N-1 条边的树, 每条边连接两 个结点,且任意两个结点存在一条路

【NOIP2016】天天爱跑步(树上差分)

题意: 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.?天天爱跑步?是一个养成类游戏,需要 玩家每天按时上线,完成打卡任务.这个游戏的地图可以看作一一棵包含 N个结点和N-1 条边的树, 每条边连接两 个结点,且任意两个结点存在一条路径互相可达.树上结点编号为从1到N的连续正整数.现在有个玩家,第个玩家的 起点为Si ,终点为Ti  .每天打卡任务开始时,所有玩家在第0秒同时从自己的起点出发, 以每秒跑一条边的速度, 不间断地沿着最短路径向着自己的终点跑去, 跑到终点后该