题目大意:给你一颗树,树上每个点都有一个观察员,他们仅会在 w[i] 时刻出现,观察正在跑步的玩家

一共有m个玩家,他们分别从节点 s[i] 同时出发,以每秒跑一条边的速度,沿着到 t[i] 的唯一路径向节点t[i]奔跑

如果一名玩家已经到达了终点,那么在他到达终点之后出现在终点的观察员不会观察到他

但如果在到达终点的同时观察员也出现在终点,那么观察员可以观察到他

求每个节点的观察员观察到玩家的数量

对于每个玩家的奔跑路线,可以拆成两部分

<1>向上跑,从 u 向 lca 奔跑

显然,玩家 u 能对观察员 i 产生1点贡献的充要条件为

显然,向上走的路线能对 i 点产生共贡献的条件是,起点 u 在 i 的子树中

我们只需要统计符合条件的即可

<2>向下跑,从 lca 向 v 奔跑

那么显然

推导可得

显然,向下走的路线能对i点产生共贡献的条件是,终点 v 在 i 的子树中

类似于上面的方法,我们只需要统计符合条件的即可

我们可以用vector在u,v,lca这三个点上打差分,存符合条件的值,注意值可能为负数

而其他子树的结果会影响答案,所以深搜统计一次答案,再用回溯的答案减去深搜的答案即可

方法比较奇葩大家凑合看吧。。。

  1. #include <cstdio>
  2. #include <algorithm>
  3. #include <cstring>
  4. #include <vector>
  5. #define N 300010
  6. #define maxn 300000
  7. using namespace std;
  8.  
  9. int n,m,cte;
  10. int dep[N],fa[N],tp[N],sz[N],son[N],ans[N];
  11. int w[N],s[N],t[N],F[N],bac[N*],head[N],tmp[N];
  12. struct EDGE{
  13. int to,nxt;
  14. }edge[N*];
  15. vector<int>S[N];
  16. vector<int>E[N];
  17. int gc()
  18. {
  19. int rett=,fh=;char p=getchar();
  20. while(p<''||p>'') {if(p=='-')fh=-;p=getchar();}
  21. while(p>=''&&p<='') {rett=rett*+p-'';p=getchar();}
  22. return rett*fh;
  23. }
  24. void edge_add(int u,int v)
  25. {
  26. cte++;
  27. edge[cte].to = v;
  28. edge[cte].nxt=head[u];
  29. head[u]=cte;
  30. }
  31. void Tsp1(int u,int dad)
  32. {
  33. for(int j=head[u];j!=-;j=edge[j].nxt)
  34. {
  35. int v=edge[j].to;
  36. if(v==dad) continue;
  37. dep[v]=dep[u]+;
  38. fa[v]=u;
  39. Tsp1(v,u);
  40. if(sz[v]>sz[son[u]]) son[u]=v;
  41. sz[u]+=sz[v];
  42. }
  43. sz[u]++;
  44. }
  45. void Tsp2(int u)
  46. {
  47. if(son[u]) tp[son[u]]=tp[u],Tsp2(son[u]);
  48. for(int j=head[u];j!=-;j=edge[j].nxt)
  49. {
  50. int v=edge[j].to;
  51. if(v==fa[u]||v==son[u]) continue;
  52. tp[v]=v;
  53. Tsp2(v);
  54. }
  55. }
  56. int LCA(int x,int y)
  57. {
  58. while(tp[x]!=tp[y])
  59. {
  60. if(dep[tp[x]]<dep[tp[y]]) swap(x,y);
  61. x=fa[tp[x]];
  62. }
  63. return dep[x]<=dep[y]?x:y;
  64. }
  65. void dfs1(int u)
  66. {
  67. tmp[u]=bac[dep[u]+w[u]+maxn];
  68. for(int j=head[u];j!=-;j=edge[j].nxt)
  69. {
  70. int v=edge[j].to;
  71. if(v==fa[u]) continue;
  72. dfs1(v);
  73. }
  74. for(int i=;i<S[u].size();i++)
  75. bac[S[u][i]+maxn]++;
  76. ans[u]+=bac[dep[u]+w[u]+maxn]-tmp[u];
  77. for(int i=;i<E[u].size();i++)
  78. bac[E[u][i]+maxn]--;
  79. }
  80. void dfs2(int u)
  81. {
  82. tmp[u]=bac[w[u]-dep[u]+maxn];
  83. for(int j=head[u];j!=-;j=edge[j].nxt)
  84. {
  85. int v=edge[j].to;
  86. if(v==fa[u]) continue;
  87. dfs2(v);
  88. }
  89. for(int i=;i<E[u].size();i++)
  90. bac[E[u][i]+maxn]--;
  91. for(int i=;i<S[u].size();i++)
  92. bac[S[u][i]+maxn]++;
  93. ans[u]+=bac[w[u]-dep[u]+maxn]-tmp[u];
  94. }
  95.  
  96. int main()
  97. {
  98. freopen("running1.in","r",stdin);
  99. //freopen("running6.out","w",stdout);
  100. scanf("%d%d",&n,&m);
  101. int x,y;
  102. memset(head,-,sizeof(head));
  103. for(int i=;i<n;i++)
  104. {
  105. x=gc(),y=gc();
  106. edge_add(x,y);
  107. edge_add(y,x);
  108. }
  109. tp[]=;
  110. Tsp1(,-);
  111. Tsp2();
  112. for(int i=;i<=n;i++) w[i]=gc();
  113. for(int i=;i<=m;i++)
  114. {
  115. s[i]=gc(),t[i]=gc();
  116. F[i]=LCA(s[i],t[i]);
  117. S[s[i]].push_back(dep[s[i]]);
  118. E[F[i]].push_back(dep[s[i]]);
  119. }
  120. //debug();
  121. dfs1();
  122. for(int i=;i<=n;i++)
  123. {
  124. S[i].clear(),E[i].clear();
  125. }
  126. memset(tmp,,sizeof(tmp));
  127. for(int i=;i<=m;i++)
  128. {
  129. S[t[i]].push_back(dep[s[i]]-*dep[F[i]]);
  130. E[F[i]].push_back(dep[s[i]]-*dep[F[i]]);
  131. }
  132. dfs2();
  133. for(int i=;i<=n;i++) printf("%d ",ans[i]);
  134. return ;
  135. }

NOIP2016 天天爱跑步 (树上差分+dfs)的更多相关文章

  1. 洛谷 1600 (NOIp2016) 天天爱跑步——树上差分

    题目:https://www.luogu.org/problemnew/show/P1600 看TJ:https://blog.csdn.net/clove_unique/article/detail ...

  2. [NOIP2016]天天爱跑步(树上差分+线段树合并)

    将每个人跑步的路径拆分成x->lca,lca->y两条路径分别考虑: 对于在点i的观察点,这个人(s->t)能被观察到的充要条件为: 1.直向上的路径:w[i]=dep[s]-dep ...

  3. NOIP2016 天天爱跑步 - 树上差分

    传送门 题目分析: 一年前还是个傻子的时候居然直接放弃了这题. 首先列出两个方程:如果i节点的观察员能够观察到由s->t的那个人,那么: \[dep[s] - dep[i] = w[i], de ...

  4. NOIP2016 Day1 T2 天天爱跑步(树上差分,LCA)

    原文链接 原题链接 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏 ...

  5. 洛谷$P1600$ 天天爱跑步 树上差分

    正解:树上差分 解题报告: 传送门$QwQ$! 这题还挺妙的,,,我想了半天才会$kk$ 首先对一条链$S-T$,考虑先将它拆成$S-LCA$和$LCA-T$,分别做.因为总体上来说差不多接下来我就只 ...

  6. 洛谷P1600 天天爱跑步——树上差分

    题目:https://www.luogu.org/problemnew/show/P1600 看博客:https://blog.csdn.net/clove_unique/article/detail ...

  7. [Noip2016]天天爱跑步 LCA+DFS

    [Noip2016]天天爱跑步 Description 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.?天天爱跑步?是一个养成类游戏,需要玩家每天按时上线,完成打卡任 ...

  8. [NOIp2016]天天爱跑步 线段树合并

    [NOIp2016]天天爱跑步 LG传送门 作为一道被毒瘤出题人们玩坏了的NOIp经典题,我们先不看毒瘤的"动态爱跑步"和"天天爱仙人掌",回归一下本来的味道. ...

  9. BZOJ 4719--天天爱跑步(LCA&差分)

    4719: [Noip2016]天天爱跑步 Time Limit: 40 Sec  Memory Limit: 512 MBSubmit: 1464  Solved: 490[Submit][Stat ...

随机推荐

  1. 封装自己的jquery框架

    jQuery is a fast small JavaScript library 如何封装自己的jQuery <script> // 这里使用沙箱模式,可以防止全局污染 (functio ...

  2. 再见,OI(2019退役祭)

    有些话应该藏在心里,有些事情只属于自己. (想了一下,自己的OI生涯.自己所经历的事情还是留在自己的心里吧,一是自己文笔不好,二是每个人的世界观不同对事情的看法不同) 不要轻易地去评价一个人,每个人背 ...

  3. [luogu2047 NOI2007] 社交网络 (floyed最短路)

    传送门 输入输出样例 输入样例#1: 4 4 1 2 1 2 3 1 3 4 1 4 1 1 输出样例#1: 1.000 1.000 1.000 1.000 题解 在进行floyed的过程中,顺便更新 ...

  4. PHP学习总结(6)——PHP入门篇之PHP语句结束符

    PHP语句结束符 有的小伙伴们是不是已经注意在每一条PHP代码行结尾处都会有一个分号:.对的,这点注意,在PHP编程中需要在每条语句的末尾加入分号:.但要注意,分号:一定在半角状态下输入噢.

  5. 公司组织oracle培训的理解

    oracle执行机制 1.客户端发送一条sql给oracle服务器,oracle会看这条sql的执行计划是否存在缓存  如果存在则直接运行,如果不存在执行第二步. 2.如果不存在缓存 则会 进行语法检 ...

  6. ZOJ 3203

    很简单的一题,注意墙上的影子是放大就行.用三分. #include <iostream> #include <cstdio> #include <cstring> ...

  7. POI进行ExcelSheet的拷贝

    POI进行ExcelSheet的拷贝 学习了:http://www.360doc.com/content/17/0508/20/42823223_652205632.shtml,这个也需要改改 这个: ...

  8. UVa 170 - Clock Patience

    题目:Clock Patience游戏,将52张扑克牌,按时钟依次分成13组(中心一组),每组4张全都背面向上, 从中间组最上面一张牌開始.翻过来设为当前值,然后取当前值相应组中最上面的背过去的牌翻过 ...

  9. @Autowired 凝视遇到的问题,@Qualifier 帮助解决这个问题

    当候选 Bean 数目不为 1 时的应对方法 在默认情况下使用 @Autowired 凝视进行自己主动注入时,Spring 容器中匹配的候选 Bean 数目必须有且仅有一个. 当找不到一个匹配的 Be ...

  10. 【VC编程技巧】窗口☞3.5对单文档或者多文档程序制作启动画面

    (一)概要: 文章描写叙述了如何通过Visual C++ 2012或者Visual C++ .NET,为单文档或者多文档程序制作启动画面.在Microsoft Visual Studio 6.0中对于 ...