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

题意:

小c同学认为跑步非常有趣,于是决定制作一款叫做《天天爱跑步》的游戏。?天天爱跑步?是一个养成类游戏,需要

玩家每天按时上线,完成打卡任务。这个游戏的地图可以看作一一棵包含 N个结点和N-1 条边的树, 每条边连接两

个结点,且任意两个结点存在一条路径互相可达。树上结点编号为从1到N的连续正整数。现在有个玩家,第个玩家的

起点为Si ,终点为Ti  。每天打卡任务开始时,所有玩家在第0秒同时从自己的起点出发, 以每秒跑一条边的速度,

不间断地沿着最短路径向着自己的终点跑去, 跑到终点后该玩家就算完成了打卡任务。 (由于地图是一棵树, 所以

每个人的路径是唯一的)小C想知道游戏的活跃度, 所以在每个结点上都放置了一个观察员。 在结点的观察员会选

择在第Wj秒观察玩家, 一个玩家能被这个观察员观察到当且仅当该玩家在第Wj秒也理到达了结点J  。 小C想知道

每个观察员会观察到多少人?注意: 我们认为一个玩家到达自己的终点后该玩家就会结束游戏, 他不能等待一 段时

间后再被观察员观察到。 即对于把结点J作为终点的玩家: 若他在第Wj秒重到达终点,则在结点J的观察员不能观察

到该玩家;若他正好在第Wj秒到达终点,则在结点的观察员可以观察到这个玩家。

思路:From http://blog.csdn.net/doyouseeman/article/details/53385565

我们思考一下从x到y的路径,
这个可以拆成从x到lca的路径和从lca到y的路径,这个很明显。
如果一个点i在从x到lca 的路径可以检测到的话,
那么就有deep[i]+w[i]=deep[x]。
如果一个点i在从lca到y的路径上可以检测到的话,
那么就有deep[i]-w[i]=deep[y]-t(t表示x到y的路径长度)。
那么用树链剖分的方法很容易,但是很慢。有一个用桶的方法,跑得很快。
维护两个桶,一个向上的桶a和一个向下的桶b。
从x到y的一个路径,在x中a[deep[x]]加一个,当dfs把lca退栈的时候,x的影响就没有了,那么把a[deep[x]]减掉。
在lca那里需要把一个b[deep[y]]加进来,在y出栈后,就把b[deep[y]]减掉。
每次ans[x]的答案就是子树a[deep[x]+w[x]]+b[deep[x]-w[x]]的数量。
但是如果是一条链的情况,那么这样会算重,所以还要减去重复的数量。

  1 var shang,xia:array[-310000..310000]of longint;
  2     head,head1,head2,head3:array[1..6100000]of longint;
  3     vet,vet1,vet2,vet3,
  4     next,next1,next2,next3,ans,dep,a,s:array[1..610000]of longint;
  5     f:array[1..310000,0..20]of longint;
  6     n,m,i,x,y,q,b,tot,tot1,tot2,tot3,t:longint;
  7
  8 procedure add(a,b:longint);
  9 begin
 10  inc(tot);
 11  next[tot]:=head[a];
 12  vet[tot]:=b;
 13  head[a]:=tot;
 14 end;
 15
 16 procedure add1(a,b:longint);
 17 begin
 18  inc(tot1);
 19  next1[tot1]:=head1[a];
 20  vet1[tot1]:=b;
 21  head1[a]:=tot1;
 22 end;
 23
 24 procedure add2(a,b:longint);
 25 begin
 26  inc(tot2);
 27  next2[tot2]:=head2[a];
 28  vet2[tot2]:=b;
 29  head2[a]:=tot2;
 30 end;
 31
 32 procedure add3(a,b:longint);
 33 begin
 34  inc(tot3);
 35  next3[tot3]:=head3[a];
 36  vet3[tot3]:=b;
 37  head3[a]:=tot3;
 38 end;
 39
 40 procedure dfs(u,fa:longint);
 41 var e,v,i:longint;
 42 begin
 43  for i:=1 to 20 do
 44  begin
 45   if dep[u]<(1<<i) then break;
 46   f[u,i]:=f[f[u,i-1],i-1];
 47  end;
 48  e:=head[u];
 49  while e<>0 do
 50  begin
 51   v:=vet[e];
 52   if v<>fa then
 53   begin
 54    f[v,0]:=u;
 55    dep[v]:=dep[u]+1;
 56    dfs(v,u);
 57   end;
 58   e:=next[e];
 59  end;
 60 end;
 61
 62 procedure swap(var x,y:longint);
 63 var t:longint;
 64 begin
 65  t:=x; x:=y; y:=t;
 66 end;
 67
 68 function lca(x,y:longint):longint;
 69 var i,d:longint;
 70 begin
 71  if dep[x]<dep[y] then swap(x,y);
 72  d:=dep[x]-dep[y];
 73  for i:=0 to 20 do
 74   if d and (1<<i)>0 then x:=f[x,i];
 75  for i:=20 downto 0 do
 76   if f[x,i]<>f[y,i] then
 77   begin
 78    x:=f[x,i]; y:=f[y,i];
 79   end;
 80  if x=y then exit(x);
 81  exit(f[x,0]);
 82 end;
 83
 84 procedure dfs1(u,fa:longint);
 85 var e,v,x,y:longint;
 86 begin
 87  x:=xia[dep[u]+a[u]];
 88  y:=shang[dep[u]-a[u]];
 89  xia[dep[u]]:=xia[dep[u]]+s[u];
 90  e:=head1[u];
 91  while e<>0 do
 92  begin
 93   v:=vet1[e];
 94   inc(shang[v]);
 95   e:=next1[e];
 96  end;
 97  e:=head[u];
 98  while e<>0 do
 99  begin
100   v:=vet[e];
101   if v<>fa then dfs1(v,u);
102   e:=next[e];
103  end;
104  ans[u]:=xia[dep[u]+a[u]]+shang[dep[u]-a[u]]-x-y;
105  e:=head2[u];
106  while e<>0 do
107  begin
108   v:=vet2[e];
109   dec(xia[v]);
110   if v=dep[u]+a[u] then dec(ans[u]);
111   e:=next2[e];
112  end;
113  e:=head3[u];
114  while e<>0 do
115  begin
116   v:=vet3[e];
117   dec(shang[v]);
118   e:=next3[e];
119  end;
120 end;
121
122 begin
123  assign(input,‘bzoj4719.in‘); reset(input);
124  assign(output,‘bzoj4719.out‘); rewrite(output);
125  readln(n,m);
126  for i:=1 to n-1 do
127  begin
128   readln(x,y);
129   add(x,y); add(y,x);
130  end;
131  dfs(1,0);
132  for i:=1 to n do read(a[i]);
133  for i:=1 to m do
134  begin
135   readln(x,y);
136   q:=lca(x,y);
137   t:=dep[x]+dep[y]-2*dep[q];
138   inc(s[x]); b:=dep[y]-t;
139   add1(y,b);
140   add2(q,dep[x]);
141   add3(q,b);
142  end;
143  dfs1(1,0);
144  for i:=1 to n-1 do write(ans[i],‘ ‘);
145  write(ans[n]);
146  close(input);
147  close(output);
148 end.
时间: 2024-11-02 17:48:21

【NOIP2016】天天爱跑步(树上差分)的相关文章

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

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

Luogu P1600 天天爱跑步 树上差分

Luogu P1600 天天爱跑步 ### 树上差分 题目链接 树上问题 没看出怎么差分 被观察到的条件有两个 lca前一半(包括lca) \(d[S_i]-d[x]=w[x]\) \(d[i]\)表示节点深度 lca后一半 \(d[S_i]+d[x]-2*d[lca(S_i,T_i)]=w[x]\) 但是具体怎么实现这个公式?? 实现 \(d[S_i]=w[x]+d[x]\) 可以转化为线段树合并模型 在\(S_i\)到\(lca\)的路径上增加\(d[S_i]\)的价值 最后求出各点的\(w

luogu P1600 天天爱跑步 |树上差分+LCA

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

NOIP2016天天爱跑步

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

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 条边的树, 每条边连接两 个结点,且任意两个结点存在一条路

bzoj 4719: [Noip2016]天天爱跑步

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

bzoj4719[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 天天爱跑步 正解

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

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向上跳的,所以可以得到式