经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
[NOIP2016]天天爱跑步-题解
来源:cnblogs  作者:frank3215  时间:2019/10/8 9:32:35  对本文有异议

题面传送门

解答

设第\(j\)号玩家在\(V_j\)时刻出发。

弱化问题:如果树退化成了一条链。则在\(j\)处的观察员能观察到的\(i\)号玩家当且仅当
\[ i玩家经过j,且 \begin{cases} dep_j - W_j = dep_{S_i} - V_j, &i向下跑步 \dep_j + W_j = dep_{S_i} + V_j, &i向上跑步 \end{cases} \]
一个点在树上的贡献是连续的,可以考虑把路径在LCA处(倍增找LCA)拆成两条链用离线+树上差分统计人经过每个点的时刻。

树上差分

如何只让一段树上的链被更新呢?(类比左闭右开区间,考虑下端为“闭”节点,上端为“开”节点的链)

考虑树上的一个点,只有链的一端在它的子树内部时才被链覆盖。
所以在dfs子树之前记下答案,在dfs之后更新链端点,真的答案就是答案的差。

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int mx = 3e5+10, LOG = 20, inf = 1e9;
  4. int n, m, ans[mx], s[mx], t[mx], w[mx];
  5. int head[mx], nxt[mx<<1], to[mx<<1], tot;
  6. int dep[mx] = {-1}, fa[mx][LOG];
  7. int down[mx<<2], up[mx<<1];
  8. vector<pair<int, int> > v[mx];
  9. void add(int u, int v) {
  10. ++tot;
  11. nxt[tot] = head[u];
  12. to[tot] = v;
  13. head[u] = tot;
  14. }
  15. void dfs0(int u) {
  16. for (int i = 1; i < LOG; ++i) {
  17. fa[u][i] = fa[fa[u][i-1]][i-1];
  18. }
  19. for (int e = head[u], v; e; e = nxt[e]) {
  20. if ((v=to[e]) == fa[u][0]) continue;
  21. fa[v][0] = u;
  22. dep[v] = dep[u]+1;
  23. dfs0(v);
  24. }
  25. }
  26. int lca(int u, int v) {
  27. if (dep[u] < dep[v]) swap(u, v);
  28. for (int i = LOG-1; ~i; --i)
  29. if (dep[fa[u][i]] >= dep[v])
  30. u = fa[u][i];
  31. if (u == v) return u;
  32. for (int i = LOG-1; ~i; --i)
  33. if (fa[u][i] != fa[v][i])
  34. u = fa[u][i], v = fa[v][i];
  35. return fa[u][0];
  36. }
  37. #define pb push_back
  38. #define mp make_pair
  39. #define fi first
  40. #define se second
  41. void addr(int s, int t, int w=0) {
  42. assert(dep[s] != dep[t]);
  43. if (dep[s] < dep[t]) w += inf, swap(s, t);
  44. v[s].pb(mp(w, 1));
  45. v[t].pb(mp(w, -1));
  46. }
  47. void dfs(int u) {
  48. ans[u] -= up[dep[u]+w[u]] + down[(mx<<1) + dep[u]-w[u]];
  49. for (int e = head[u]; e; e = nxt[e]) {
  50. if (to[e] == fa[u][0]) continue;
  51. dfs(to[e]);
  52. }
  53. for (int i = 0; i < (int)v[u].size(); ++i) {
  54. if (v[u][i].fi > inf/2) down[(mx<<1) + v[u][i].fi-inf] += v[u][i].se;
  55. else up[v[u][i].fi] += v[u][i].se;
  56. }
  57. ans[u] += up[dep[u]+w[u]] + down[(mx<<1) + dep[u]-w[u]];
  58. }
  59. int main() {
  60. scanf("%d%d", &n, &m);
  61. int u, v;
  62. for (int i = 0; i < n-1; ++i) {
  63. scanf("%d%d", &u, &v);
  64. add(u, v), add(v, u);
  65. }
  66. dfs0(1);
  67. for (int i = 1; i <= n; ++i) scanf("%d", w+i);
  68. for (int i = 1; i <= m; ++i) {
  69. scanf("%d%d", s+i, t+i);
  70. u = lca(s[i], t[i]);
  71. if (u == s[i]) addr(fa[s[i]][0], t[i], dep[s[i]]);
  72. else if (u == t[i]) addr(s[i], fa[t[i]][0], dep[s[i]]);
  73. else {
  74. addr(s[i], fa[u][0], dep[s[i]]);
  75. addr(u, t[i], dep[u] - (dep[s[i]]-dep[u]));
  76. }
  77. }
  78. dfs(1);
  79. for (int i = 1; i <= n; ++i) printf("%d%c", ans[i], " \n"[i==n]);
  80. }

原文链接:http://www.cnblogs.com/topsecret/p/noip2016-running.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号