http://www.lydsy.com/JudgeOnline/problem.php?id=3924

gty的测试题,不会动态点分治而且看不出来链剖做法而且暴力打残所以这道题喜闻乐见的爆零了qwq

动态点分治:设重心重构树上以x为根的子树为\(T_x\),在重心重构树上每个点维护3个值。

\(sum(x)=\sum\limits_{u\in T_x}d(u)\)

\(ans(x)=\sum\limits_{u\in T_x}d(u)*dis(u,x)\)

\(ans\_fa(x)=\sum\limits_{u\in T_x}d(u)*dis(u,fa(x))\)

其中,\(dis\)指的是原树上的两点间距离,这个可以用st表\(O(1)\)求出;\(fa(x)\)指的是重心重构树上x的父亲。

每次修改x时,在重心重构树上不断地往上跳同时维护这三个值就可以了。

要查询一个点的花费(这里的花费指的在整棵树上的花费),类似修改,从重心重构树上不断地往上跳并统计答案(\(ans\_fa\)很明显是用来减掉自身贡献的)。

查询时从重心重构树的树根开始,枚举当前点在原树上连向更小分治块的边,检查这些边直接连着的点的花费。要是没有比当前点小的,答案就是当前点的花费;否则当前点跳到此时花费最小的点所在的下一级分治块的重心,继续检查。

感性理解:因为任意一条链上的点的花费是单峰的(峰向下),每次都向峰靠拢,所以这么做是正确的。

又因为重心重构树的树高是\(O(\log n)\)的,查询一个点的花费的时间复杂度是\(O(\log n)\),所以总时间复杂度是\(O(n\log n+q\log^2n*d)\)。

d指的是检查的所有点的平均度数,因为cls原题面中说明了每个点的度不超过20,所以这样可过。

这道题适合做动态点分治的模板题啊qwq

  1. #include<vector>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. using namespace std;
  6. typedef long long ll;
  7. const int N = 100003;
  8. namespace RE {
  9. struct node {int nxt, to, w;} E[N];
  10. int cnt = 0, point[N], fa[N];
  11. ll sum[N], ans[N], ans_fa[N];
  12. void ins(int u, int v) {E[++cnt] = (node) {point[u], v}; point[u] = cnt; fa[v] = u;}
  13. }
  14. namespace ORG {
  15. struct node {int nxt, to, w;} E[N << 1];
  16. int cnt = 0, point[N];
  17. bool vis[N];
  18. vector <pair <int, int> > ref[N];
  19. void ins(int u, int v, int e) {E[++cnt] = (node) {point[u], v, e}; point[u] = cnt;}
  20. int qu[N], fa[N], sz[N];
  21. int findrt(int x) {
  22. fa[qu[1] = x] = 0;
  23. int p = 0, q = 1, u;
  24. while (p != q) {
  25. sz[u = qu[++p]] = 0;
  26. for (int i = point[u]; i; i = E[i].nxt)
  27. if (E[i].to != fa[u] && !vis[E[i].to])
  28. fa[E[i].to] = u, qu[++q] = E[i].to;
  29. }
  30. for (int i = q; i >= 1; --i) {
  31. sz[fa[qu[i]]] += (++sz[qu[i]]);
  32. if ((sz[qu[i]] << 1) > q)
  33. return qu[i];
  34. }
  35. }
  36. int root;
  37. void dfs(int x) {
  38. vis[x] = true;
  39. for (int i = point[x]; i; i = E[i].nxt)
  40. if (!vis[E[i].to]) {
  41. root = findrt(E[i].to);
  42. ref[x].push_back(make_pair(E[i].to, root));
  43. RE::ins(x, root);
  44. dfs(root);
  45. }
  46. }
  47. int L[N], wat[N << 1], tt = 0;
  48. ll f[N << 1][19], deep[N];
  49. void dfs2(int x, int ff) {
  50. wat[L[x] = ++tt] = x;
  51. for (int i = point[x]; i; i = E[i].nxt)
  52. if (E[i].to != ff) {
  53. deep[E[i].to] = deep[x] + E[i].w;
  54. dfs2(E[i].to, x);
  55. wat[++tt] = x;
  56. }
  57. }
  58. int Log_2[N << 1], rt;
  59. void pre() {
  60. dfs2(1, 0);
  61. Log_2[1] = 0; int cc = 0;
  62. for (int i = 2; i <= tt; ++i) {
  63. Log_2[i] = cc;
  64. if ((1 << (cc + 1)) == i)
  65. ++cc;
  66. }
  67. for (int i = 1; i <= tt; ++i)
  68. f[i][0] = deep[wat[i]];
  69. for (int j = 1; j <= 18; ++j)
  70. for (int i = (1 << j); i <= tt; ++i)
  71. f[i][j] = min(f[i][j - 1], f[i - (1 << (j - 1))][j - 1]);
  72. rt = 1; while (RE::fa[rt]) rt = RE::fa[rt];
  73. }
  74. int len;
  75. ll dis(int x, int y) {
  76. ll r = deep[x] + deep[y];
  77. x = L[x]; y = L[y];
  78. if (x > y) x ^= y ^= x ^= y;
  79. len = Log_2[y - x + 1];
  80. ll dlca = min(f[y][len], f[x - 1 + (1 << len)][len]);
  81. return r - (dlca << 1);
  82. }
  83. ll query(int x) {
  84. ll ret = RE::ans[x], retf;
  85. int ff, tmp = x;
  86. while (true) {
  87. if ((ff = RE::fa[tmp]) == 0) return ret;
  88. retf = RE::ans[ff] - RE::ans_fa[tmp];
  89. ret += retf + (RE::sum[ff] - RE::sum[tmp]) * dis(x, ff);
  90. tmp = ff;
  91. }
  92. }
  93. void change(int x, int e) {
  94. int tmp = x;
  95. while (true) {
  96. RE::sum[tmp] += e;
  97. RE::ans[tmp] += dis(x, tmp) * e;
  98. if (RE::fa[tmp]) {
  99. RE::ans_fa[tmp] += dis(x, RE::fa[tmp]) * e;
  100. tmp = RE::fa[tmp];
  101. } else
  102. return;
  103. }
  104. }
  105. ll ansit() {
  106. int tmp = rt, an = tmp, len;
  107. pair <int, int> ann;
  108. ll annow, cmpan, rr;
  109. while (true) {
  110. cmpan = annow = query(tmp);
  111. for (int i = 0, len = ref[tmp].size(); i < len; ++i)
  112. if ((rr = query(ref[tmp][i].first)) < annow)
  113. annow = rr, ann = ref[tmp][i];
  114. if (annow != cmpan)
  115. tmp = ann.second;
  116. else
  117. return annow;
  118. }
  119. }
  120. }
  121. int n;
  122. int main() {
  123. int q;
  124. scanf("%d%d", &n, &q);
  125. int u, v, e;
  126. for (int i = 1; i < n; ++i) {
  127. scanf("%d%d%d", &u, &v, &e);
  128. ORG::ins(u, v, e);
  129. ORG::ins(v, u, e);
  130. }
  131. ORG::dfs(ORG::findrt(1));
  132. ORG::pre();
  133. while (q--) {
  134. scanf("%d%d", &u, &e);
  135. ORG::change(u, e);
  136. printf("%lld\n", ORG::ansit());
  137. }
  138. return 0;
  139. }

【BZOJ 3924】【ZJOI 2015】幻想乡战略游戏的更多相关文章

  1. [ZJOI 2015]幻想乡战略游戏

    Description 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来, ...

  2. 【BZOJ 3924】[Zjoi2015]幻想乡战略游戏

    题目: 题解: 对点分树理解加深了233,膜拜zzh干翻紫荆花. 感谢zzh的讲解. 首先优化基于传统DP,假设树不发生变化,我们就可以利用DP求出带权重心. 考虑修改,我们思路不变,还是从root开 ...

  3. ZJOI 2015 幻想乡战略游戏(动态点分治)

    题意 https://loj.ac/problem/2135 思路 首先要明确一点,答案分布是有单调性的.什么意思呢?假设我们的答案在 \(u\) 节点,\((u,v)\) 之间有一条边且 \(u\) ...

  4. 解题:ZJOI 2015 幻想乡战略游戏

    题面 神**所有点都爆int,我还以为我写出什么大锅了,不开long long见祖宗... 动态点分治利用点分树树高不超过log的性质,我们对每个点维护一个子树和,一个点分树子树和,一个点分树上父亲的 ...

  5. bzoj3924 [Zjoi2015]幻想乡战略游戏 点分树,动态点分

    [BZOJ3924][Zjoi2015]幻想乡战略游戏 Description 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网 ...

  6. 【BZOJ3924】幻想乡战略游戏(动态点分治)

    [BZOJ3924]幻想乡战略游戏(动态点分治) 题面 权限题...(穷死我了) 洛谷 题解 考虑不修改 发现一个贪心的做法 假设当前放在当前位置 如果它有一个子树的兵的总数大于总数的一半 那么,放到 ...

  7. LOJ2135 「ZJOI2015」幻想乡战略游戏

    题意 题目描述 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做越大,以至于幽香一眼根本看不过来,更别说和 ...

  8. LOJ #2135. 「ZJOI2015」幻想乡战略游戏

    #2135. 「ZJOI2015」幻想乡战略游戏 链接 分析: 动态点分治,求加权重心,带修改. 考虑如果知道了一个点s,如何求答案,那么首先可以点分治的思想,求每个联通块内所有点到分治中心距离和,然 ...

  9. 洛谷 P3345 [ZJOI2015]幻想乡战略游戏 解题报告

    P3345 [ZJOI2015]幻想乡战略游戏 题目描述 傲娇少女幽香正在玩一个非常有趣的战略类游戏,本来这个游戏的地图其实还不算太大,幽香还能管得过来,但是不知道为什么现在的网游厂商把游戏的地图越做 ...

  10. [ZJOI2015]幻想乡战略游戏——动态点分治

    [ZJOI2015]幻想乡战略游戏 带修改下,边点都带权的重心 随着变动的过程中,一些子树内的点经过会经过一些公共边.考虑能不能对这样的子树一起统计. 把树上贡献分块. 考虑点分治算法 不妨先把题目简 ...

随机推荐

  1. 如何免费上传4G以上大文件至百度云网盘

    百度云网盘的容量高达2048G,因而如今使用百度云网盘的用户也越来越多, 但是百度云中如果要上传超过4G的大文件,必须要升级VIP才行,但这需要收费.那么,超过4G以上的大文件我们该怎样上传到百度云呢 ...

  2. python中正则用法举例

    一.根据正则表达式替换字符串 import re text='abc123' text=re.sub(r'\d','-',text) print(text) 输出:abc---将每个数字替换为-,如果 ...

  3. 集合框架源码学习之ArrayList

    目录: 0-0-1. 前言 0-0-2. 集合框架知识回顾 0-0-3. ArrayList简介 0-0-4. ArrayList核心源码 0-0-5. ArrayList源码剖析 0-0-6. Ar ...

  4. sql 自定义split

    以下数据库操作针对sql server. 问题来源:由于项目中,有的表字段内容是由多个id或多个其他内容拼接而成.(如:'1,2,3,4,5',或者'name_age_school'),特点是都用某个 ...

  5. Intel call指令

    转载:http://blog.ftofficer.com/2010/04/n-forms-of-call-instructions/ 最近有一个需求,给你个地址,看看这个地址前面是不是一个CALL指令 ...

  6. FineReport——权限分配以及自定义首页

    权限分配可以有两种方法,第一种方法是根据部门职位分配权限,第二种是根据角色分配权限: FR自带有三个JQ对象,用以保存用户名参数/角色参数/部门参数——$fr_username/$fr_authori ...

  7. MySQL数据库分表分区(一)(转)

    面对当今大数据存储,设想当mysql中一个表的总记录超过1000W,会出现性能的大幅度下降吗? 答案是肯定的,一个表的总记录超过1000W,在操作系统层面检索也是效率非常低的   解决方案: 目前针对 ...

  8. http通信过程中,Web浏览器与Web服务器之间将完成下列7个步骤

    http通信过程中,Web浏览器与Web服务器之间将完成下列7个步骤: (1)    建立TCP连接 在HTTP工作开始之前,Web浏览器首先要通过网络与Web服务器建立连接,该连接是通过TCP来完成 ...

  9. [PAT] 1147 Heaps(30 分)

    1147 Heaps(30 分) In computer science, a heap is a specialized tree-based data structure that satisfi ...

  10. XAlign—自动对齐代码插件

    XAlign An amazing Xcode plugin to align regular code. It can align anything by using custom alignmen ...