link

给定一棵树,点有点权,边有边权,你每次修改一个点点权或者是修改一个边边权

你一开始在1号点,你每次改节点之后你需要移动到另一个节点,满足这个节点权值减去路径长度最大(下一次从这个节点移动)如果存在相同的收益,选编号最小的节点

你需要输出每次移动到的节点坐标

题解:

处理树上多条路径可以用动态淀粉质

考虑动态淀粉质,对于点分树上每个点开个线段树,下标为点分树子树中的节点,权值为这个点到子节点的收益,同时维护最大值的坐标

对于点权的修改,可以直接在点分树上暴力跳父亲

对于一条边的修改,考虑从这条边连接两个点中点分树上深度较浅的节点向上暴力跳父亲

假设当前我们跳的是 i,我们需要找x和y中哪个点在以 i 为根原树中深度最大,找那个深度大的点,发现这条边的更改影响的点恰好是这个深度较大的点的子树 所以对于每个点分树子树,我们维护一个dfs序,开线段树时按照dfs序存储(注意判断下标还要按照原编号判断),那么这个操作就是一个区间修改

查询时候还是暴力跳父亲,直接查询每个父亲中子树中除了这个点的最大值,就是一个区间查询

注意要减去父亲到这个点的距离,这个可以单点查询查出来

  1. #include <cstdio>
  2. #include <map>
  3. #include <vector>
  4. using namespace std;
  5. int n, q, sum, rt, tot;
  6. long long val[100010], ltmp; // 点权
  7. vector<pair<int, long long>> out[100010]; // 假装它是链式前向星
  8. bool vis[100010]; // 构建点分树用的临时数组,最后是true
  9. int sz[100010][20]; // i 在他的点分树深度为 j 的父亲的子树大小, 第二维 0 为构建点分树临时数组
  10. int maxw[100010]; // 构建点分树的临时数组
  11. long long dist[100010]; // 临时的距离数组
  12. int depth[100010]; // 点分树深度
  13. int deep[100010][20]; // i 在以它深度为 j 的点分树父亲为根时的深度
  14. int father[100010][20]; // i 的深度为 j 的父亲
  15. int dfn[100010][20]; // i 在他的点分树深度为 j 的父亲的dfn
  16. vector<int> id[100010]; // 子树中对应的
  17. struct data { int pos, rt; long long val; } tree[10000010]; //线段树
  18. int lc[10000010], rc[10000010], segtot = 0, segrt[100010]; //左右儿子,每个点的线段树根
  19. long long lazy[10000010]; //线段树lazytag
  20. void chkmax(int &a, int b) { if (a < b) a = b; }
  21. data operator+(const data &a, const data &b)
  22. {
  23. if (a.val != b.val) return a.val > b.val ? a : b;
  24. if (a.rt == -1) return b;
  25. if (b.rt == -1) return a;
  26. return id[a.rt][a.pos - 1] < id[b.rt][b.pos - 1] ? a : b;
  27. }
  28. int build(int cl, int cr, int rt)
  29. {
  30. int x = ++segtot;
  31. if (cl != cr)
  32. {
  33. int mid = (cl + cr) / 2;
  34. lc[x] = build(cl, mid, rt), rc[x] = build(mid + 1, cr, rt), tree[x] = tree[lc[x]] + tree[rc[x]];
  35. }
  36. else tree[x].pos = cl, tree[x].rt = rt;
  37. return x;
  38. }
  39. void pushdown(int x)
  40. {
  41. tree[lc[x]].val += lazy[x], tree[rc[x]].val += lazy[x];
  42. lazy[lc[x]] += lazy[x], lazy[rc[x]] += lazy[x], lazy[x] = 0;
  43. }
  44. void chenge(int x, int cl, int cr, int L, int R, long long val)
  45. {
  46. if (L <= cl && cr <= R) { tree[x].val += val, lazy[x] += val; return; }
  47. pushdown(x);
  48. int mid = (cl + cr) / 2;
  49. if (L <= mid) chenge(lc[x], cl, mid, L, R, val);
  50. if (R > mid) chenge(rc[x], mid + 1, cr, L, R, val);
  51. tree[x] = tree[lc[x]] + tree[rc[x]];
  52. }
  53. data chuans(int x, int cl, int cr, int L, int R)
  54. {
  55. if (L > R) return (data){0, -1, -9223372036854775807LL};
  56. if (L <= cl && cr <= R) return tree[x];
  57. pushdown(x);
  58. int mid = (cl + cr) / 2;
  59. if (R <= mid) return chuans(lc[x], cl, mid, L, R);
  60. if (L > mid) return chuans(rc[x], mid + 1, cr, L, R);
  61. return chuans(lc[x], cl, mid, L, R) + chuans(rc[x], mid + 1, cr, L, R);
  62. }
  63. void getrt(int x, int fa)
  64. {
  65. sz[x][0] = 1, maxw[x] = 0;
  66. for (pair<int, long long> i : out[x]) if (fa != i.first && vis[i.first] == false)
  67. getrt(i.first, x), sz[x][0] += sz[i.first][0], chkmax(maxw[x], sz[i.first][0]);
  68. chkmax(maxw[x], sum - sz[x][0]); if (maxw[x] < maxw[rt]) rt = x;
  69. }
  70. void getsz(int x, int fa, int rt)
  71. {
  72. sz[x][depth[rt]] = 1, father[x][depth[rt]] = rt, dfn[x][depth[rt]] = ++tot, id[rt].push_back(x);
  73. for (pair<int, long long> i : out[x]) if (fa != i.first && vis[i.first] == false)
  74. getsz(i.first, x, rt), sz[x][depth[rt]] += sz[i.first][depth[rt]];
  75. }
  76. void getdis(int x, int fa, int rt)
  77. {
  78. chenge(segrt[rt], 1, sz[rt][depth[rt]], dfn[x][depth[rt]], dfn[x][depth[rt]], val[x] - dist[x]);
  79. for (pair<int, long long> i : out[x]) if (fa != i.first && vis[i.first] == false)
  80. dist[i.first] = dist[x] + i.second, deep[i.first][depth[rt]] = deep[x][depth[rt]] + 1, getdis(i.first, x, rt);
  81. }
  82. void solve(int x, int d)
  83. {
  84. vis[x] = true, depth[x] = d, tot = 0, getsz(x, 0, x);
  85. segrt[x] = build(1, sz[x][depth[x]], x), dist[x] = 0, deep[x][depth[x]] = 0, getdis(x, 0, x);
  86. for (pair<int, long long> i : out[x]) if (vis[i.first] == false)
  87. sum = sz[i.first][depth[x]], rt = 0, getrt(i.first, 0), solve(rt, d + 1);
  88. }
  89. int main()
  90. {
  91. map<pair<int, int>, long long> e;
  92. scanf("%d%d", &n, &q);
  93. for (int i = 1; i <= n; i++) scanf("%lld", &val[i]);
  94. for (int x, y, i = 1; i < n; i++)
  95. {
  96. scanf("%d%d%lld", &x, &y, &ltmp);
  97. out[x].push_back(make_pair(y, ltmp));
  98. out[y].push_back(make_pair(x, ltmp));
  99. if (x > y) swap(x, y);
  100. e[make_pair(x, y)] = ltmp;
  101. }
  102. maxw[0] = sum = n, getrt(1, 0), solve(rt, 1);
  103. int pos = 1;
  104. for (int opt, x, y, t = 1; t <= q; t++)
  105. {
  106. scanf("%d", &opt);
  107. if (opt == 1)
  108. {
  109. scanf("%d%lld", &x, &ltmp);
  110. for (int i = x; i != 0; i = father[i][depth[i] - 1])
  111. chenge(segrt[i], 1, sz[i][depth[i]], dfn[x][depth[i]], dfn[x][depth[i]], ltmp - val[x]);
  112. val[x] = ltmp;
  113. }
  114. if (opt == 2)
  115. {
  116. scanf("%d%d%lld", &x, &y, &ltmp);
  117. if (x > y) swap(x, y);
  118. long long delta = ltmp - e[make_pair(x, y)];
  119. e[make_pair(x, y)] = ltmp;
  120. if (depth[x] < depth[y]) swap(x, y);
  121. for (int i = y; i != 0; i = father[i][depth[i] - 1])
  122. {
  123. if (deep[y][depth[i]] > deep[x][depth[i]]) { swap(x, y); }
  124. chenge(segrt[i], 1, sz[i][depth[i]], dfn[x][depth[i]], dfn[x][depth[i]] + sz[x][depth[i]] - 1, -delta);
  125. }
  126. }
  127. data ans = (data){0, -1, -9223372036854775807LL};
  128. for (int i = pos; i > 0; i = father[i][depth[i] - 1])
  129. {
  130. data tmp = chuans(segrt[i], 1, sz[i][depth[i]], 1, dfn[pos][depth[i]] - 1) + chuans(segrt[i], 1, sz[i][depth[i]], dfn[pos][depth[i]] + 1, sz[i][depth[i]]);
  131. tmp.val += chuans(segrt[i], 1, sz[i][depth[i]], dfn[pos][depth[i]], dfn[pos][depth[i]]).val - val[pos];
  132. ans = ans + tmp;
  133. }
  134. printf("%d%c", pos = id[ans.rt][ans.pos - 1], t == q ? '\n' : ' ');
  135. }
  136. return 0;
  137. }

loj2497 [PA2017]Banany(动态淀粉质)的更多相关文章

  1. 动态淀粉质(划掉)题单&简要题解

    简介 动态点分治的思想:还不太清楚诶怎么办. 大概是通过降低树高来降低每次修改和询问的复杂度吧,还可以把树上一个连通块的信息统计到一个点(重心)上.具体实现方式和普通的静态点分治没有太大的区别,只是把 ...

  2. 淀粉质模板 Tree

    Tree 题目描述 给你一棵TREE,以及这棵树上边的距离.问有多少对点它们两者间的距离小于等于K 输入输出格式 输入格式: N(n<=40000) 接下来n-1行边描述管道,按照题目中写的输入 ...

  3. 题解 洛谷 P4695 【[PA2017]Banany】

    考虑用动态点分治来解决像本题这样带修的树上路径问题. 首先对原树进行点分治,建出点分树,在点分树每个节点上用动态开点线段树来维护以该节点为起点,到其点分树子树中每个节点的利润. 查询时只需在点分树上当 ...

  4. 2017-12 CDQZ集训(已完结)

    从联赛活了下来(虽然分数倒一……),接下来要去CDQZ集训啦…… DAY -2 2017-12-16 被老师安排负责一部分同学的住宿以及安排…… 抓紧时间继续学习,LCT真好玩啊真好玩…… 晚上放假了 ...

  5. [HNOI2015]开店 树链剖分,主席树

    [HNOI2015]开店 LG传送门 蒟蒻表示不会动态淀粉质. 先把点按年龄排序, 设\(dis[i]\)表示\(i\)到根的距离. 把我们要算的东西稍微变下形:\(ans\) \[ = \sum \ ...

  6. 点分治&&动态点分治学习笔记

    突然发现网上关于点分和动态点分的教程好像很少……蒟蒻开篇blog记录一下吧……因为这是个大傻逼,可能有很多地方写错,欢迎在下面提出 参考文献:https://www.cnblogs.com/LadyL ...

  7. 【ZJOI2007】捉迷藏 小小的总结

    2019-01-09 22:56:33 终于终于把这道题目做掉了... 做了两个晚上..不知道为什么自己如此之笨.. 在洛谷上断断续续一共交了24次,感觉自己都要被封号了. 昨天花半个晚上从零开始研究 ...

  8. 洛谷$P$3241 开店 $[HNOI2015]$ 主席树/点分治

    正解:主席树/动态点分治 解题报告: 传送门! $umm$淀粉质的话要是动态的我还不会$QAQ$,,,所以先写下主席树的题解昂$QwQ$ 题目大意是说,给定一棵树,树上每个点都有个值,然后有若干个询问 ...

  9. [Updating]点分治学习笔记

    Upd \(2020/2/15\),又补了一题 LuoguP2664 树上游戏 \(2020/2/14\),补了一道例题 LuoguP3085 [USACO13OPEN]阴和阳Yin and Yang ...

随机推荐

  1. Opencv HOG特征检测

    HOGDescriptor hogDescriptor = HOGDescriptor(); hogDescriptor.setSVMDetector(hogDescriptor.getDefault ...

  2. 15-Call to your teacher(有向图的连通判断)

    链接:https://www.nowcoder.net/acm/contest/76/F来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K,其他语言65536K ...

  3. ZPL语言说明文档

    ■格式命令(format commands) 以︿开始 用于设定标签格式与数据 多条格式指令按顺序执行 ■控制指令(control commands) 以~开始 迫使打印机立即执行某一个指令的操作 可 ...

  4. char a[] = "hello world1"和char *p = "hello world2";的区别(转)

    转自:jianchi88 http://blog.csdn.net/jianchi88/article/details/6876405 #include<stdio.h> int main ...

  5. es学习-索引配置

    1.创建一个新的索引并且添加一个配置 2.更新索引配置:(更新分词器为例子) 更新分词器前,一定要关闭索引,然后更新,最后再次开启索引 url:PUT http://127.0.0.1:9200/su ...

  6. 借助LVS+Keepalived实现负载均衡(转)

    出处:http://www.cnblogs.com/edisonchou/p/4281978.html 一.负载均衡:必不可少的基础手段 1.1 找更多的牛来拉车吧 当前大多数的互联网系统都使用了服务 ...

  7. 【Windows】ASP.NET Core 部署到 IIS

    如果你的系统环境没有 .NET CORE SDK,请到官网进行下载: https://www.microsoft.com/net/download/windows 接下来我们开始进行环境的部署,首先在 ...

  8. 编写高质量代码改善C#程序的157个建议——建议128:考虑让派生类的名字以基类名字作为后缀

    建议128:考虑让派生类的名字以基类名字作为后缀 派生类的名字可以考虑以基类名字作为后缀.这带来的好处是,从类型的名字上我们就知道它包含在哪一个继承体系中. Exception及其子类就是这样一个典型 ...

  9. 20169205实验一 Java开发环境的熟悉(Linux+IDEA)

    20169205实验一 Java开发环境的熟悉(Linux+IDEA) 实验内容及步骤 使用JDK编译.运行简单的Java程序 打开windows下的cmd → 输入cd Code命令进入Code目录 ...

  10. MVC模式在Java Web应用程序中的实例分析

    MVC在软件架构中是一种比较重要的架构思想,已经被广泛的应用在实际的java web项目开发中,我们所要了解和掌握的是mvc的架构思想和使用mvc模式来分析和解决问题的方法.当然相同或不同的项目都有各 ...