Brief Description

给定一棵n个节点的带权树,节点编号为1到n,以root为根,设sum[p]表示以点p为根的这棵子树中所有节点的权

值和。支持下列两种操作:

1 给定两个整数u,v,修改点u的权值为v。

2 给定两个整数l,r,计算sum[l]+sum[l+1]+....+sum[r-1]+sum[r]

Algorithm Design

我们考察暴力算法:

对于查询,我们如果处理出所有的sum[i]就可以处理了。考虑到是树上的子树查询,我们考虑使用dfs序,使用BIT维护即可,这个算法是\(\Theta(log n)\)的。

对于修改,如果我们能够记录每个点是否可以被这个修改的点影响,我们就可以扫一遍就ok了。这样的复杂度是\(\Theta(nlogn)\)的。

我们可以看到修改的复杂度比较大,我们考虑使用分块平衡一下这两个算法,假设我们\(h(n)\)分一块,

对于查询,我们可以把查询区间分为\(\Theta(\frac{n}{h(n)})\)个区间,对于每个区间直接统计,对于两边的区间直接统计复杂度\(\Theta(h(n)log(h(n))\)

对于修改,我们统计每一个区域会被修改的点修改几次,直接统计影响即可。复杂度是\(\Theta(\frac{n}{h(n)})\)

这样,算法总的复杂度就是\(\Theta(h(n)log(h(n))+\frac{n}{h(n)})\),为了方便,我们设\(h(n) = \sqrt n\)。

Code

  1. #include <cmath>
  2. #include <cstdio>
  3. #define ll unsigned long long
  4. const ll maxn = 100010;
  5. const ll maxm = 320;
  6. ll value[maxn], bit[maxn << 1], wtf[maxn];
  7. int f[maxn][maxm];
  8. int t[maxm], l[maxn], r[maxn], head[maxn], b[maxn];
  9. ll n, m, rt, ind = 0, cnt = 0, blockm, block;
  10. struct edge {
  11. ll to, next;
  12. } e[maxn << 2];
  13. ll lowbit(ll x) { return x & -x; }
  14. void change(ll pos, ll x) {
  15. for (ll i = pos; i <= n; i += lowbit(i))
  16. bit[i] += x;
  17. }
  18. ll sum(ll pos) {
  19. ll ans = 0;
  20. for (ll i = pos; i > 0; i -= lowbit(i))
  21. ans += bit[i];
  22. return ans;
  23. }
  24. void insert(ll x, ll y) {
  25. e[++cnt].to = y;
  26. e[cnt].next = head[x];
  27. head[x] = cnt;
  28. e[++cnt].to = x;
  29. e[cnt].next = head[y];
  30. head[y] = cnt;
  31. }
  32. void dfs(ll x, ll fa) {
  33. t[b[x]]++;
  34. for (ll i = 1; i <= blockm; i++)
  35. f[x][i] = t[i];
  36. l[x] = ++ind;
  37. change(l[x], value[x]);
  38. for (ll i = head[x]; i; i = e[i].next) {
  39. if (e[i].to != fa)
  40. dfs(e[i].to, x);
  41. }
  42. r[x] = ind;
  43. t[b[x]]--;
  44. }
  45. int main() {
  46. #ifndef ONLINE_JUDGE
  47. freopen("input", "r", stdin);
  48. #endif
  49. scanf("%llu %llu", &n, &m);
  50. block = (int)sqrt(n);
  51. blockm = (n - 1) / block + 1;
  52. for (ll i = 1; i <= n; i++) {
  53. scanf("%llu", &value[i]);
  54. }
  55. for (ll i = 1; i <= n; i++)
  56. b[i] = (i - 1) / block + 1;
  57. for (ll i = 1; i <= n; i++) {
  58. ll u, v;
  59. scanf("%llu %llu", &u, &v);
  60. if (u == 0)
  61. rt = v;
  62. else
  63. insert(u, v);
  64. }
  65. dfs(rt, 0);
  66. for (ll i = 1; i <= n; i++)
  67. wtf[b[i]] += sum(r[i]) - sum(l[i] - 1);
  68. for (ll i = 1; i <= m; i++) {
  69. ll op, u, v;
  70. scanf("%llu %llu %llu", &op, &u, &v);
  71. if (op == 1) {
  72. change(l[u], v - value[u]);
  73. for (ll j = 1; j <= blockm; j++)
  74. wtf[j] += 1ll * f[u][j] * (v - value[u]);
  75. value[u] = v;
  76. } else {
  77. ll ans = 0;
  78. if (b[u] == b[v])
  79. for (ll j = u; j <= v; j++)
  80. ans += sum(r[j]) - sum(l[j] - 1);
  81. else {
  82. for (ll j = b[u] + 1; j <= b[v] - 1; j++)
  83. ans += wtf[j];
  84. for (ll j = u; b[j] == b[u] && j <= n; j++)
  85. ans += sum(r[j]) - sum(l[j] - 1);
  86. for (ll j = v; b[j] == b[v] && j; j--)
  87. ans += sum(r[j]) - sum(l[j] - 1);
  88. }
  89. printf("%llu\n", ans);
  90. }
  91. }
  92. }

[bzoj4765]普通计算姬——分块的更多相关文章

  1. [BZOJ4765]普通计算姬(分块+树状数组)

    4765: 普通计算姬 Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 1725  Solved: 376[Submit][Status][Discus ...

  2. BZOJ4765: 普通计算姬

    BZOJ4765: 普通计算姬 题目描述 传送门 题目分析 求的和非常奇怪,不具有连续性,所有上树的数据结构全死了. 考虑分块,思考对于一段连续的询问区间可以直接询问整块,零散块可以在树上dfs序暴力 ...

  3. 2018.06.30 BZOJ4765: 普通计算姬(dfs序+分块+树状数组)

    4765: 普通计算姬 Time Limit: 30 Sec Memory Limit: 256 MB Description "奋战三星期,造台计算机".小G响应号召,花了三小时 ...

  4. [bzoj4765]普通计算姬(分块+树状数组+DFS序)

    题意 给定一棵n个节点的带权树,节点编号为1到n,以root为根,设sum[p]表示以点p为根的这棵子树中所有节点的权值和.计算姬支持下列两种操作: 1 给定两个整数u,v,修改点u的权值为v. 2 ...

  5. BZOJ 4765 普通计算姬 (分块 + BIT)

    4765: 普通计算姬 Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 1547  Solved: 329[Submit][Status][Discus ...

  6. BZOJ4765 普通计算姬(分块+树状数组)

    对节点按编号分块.设f[i][j]为修改j号点对第i块的影响,计算f[i][]时dfs一遍即可.记录每一整块的sum.修改时对每一块直接更新sum,同时用dfs序上的树状数组维护子树和.查询时累加整块 ...

  7. bzoj4765: 普通计算姬 (分块 && BIT)

    最近一直在刷分块啊 似乎感觉分块和BIT是超级棒的搭档啊 这道题首先用dfs预处理一下 得到每一个sum值 此时查询是O(1)的  (前缀和乱搞什么的 但是修改需要O(n) (需要修改该节点所有祖先的 ...

  8. BZOJ 4765: 普通计算姬 [分块 树状数组 DFS序]

    传送门 题意: 一棵树,支持单点修改和询问以$[l,r]$为根的子树的权值和的和 只有我这种不会分块的沙茶不会做这道题吗? 说一点总结: 子树和当然上$dfs$序了,询问原序列一段区间所有子树和,对原 ...

  9. BZOJ 4765: 普通计算姬 (分块+树状数组)

    传送门 解题思路 树上的分块题,,对于修改操作,每次修改只会对他父亲到根这条链上的元素有影响:对于查询操作,每次查询[l,r]内所有元素的子树,所以就考虑dfn序,进标记一次,出标记一次,然后子树就是 ...

随机推荐

  1. NodeJS微信公众平台开发

    微信是手机用户必备的App,微信最开始只是作为社交通讯应用供用户使用,但随着用户量不断的增加,微信的公众号在微信上表现出来了它强大的一面,微信公众平台具有四大优势:1.平台更加稳固:2.用户关系更加平 ...

  2. php 使用GD库压缩图片,添加文字图片水印

    先上一个工具类,提供了压缩,添加文字.图片水印等方法: image.class.php <?php class Image { private $info; private $image; pu ...

  3. Prolog奇怪奇妙的思考方式

    今天在<七周七语言>中接触到了prolog,发现它的编程模式和思考方式的确比较奇怪,但同时也非常奇妙,值得学习一下. 1. prolog语言介绍     和SQL一样,Prolog基于数据 ...

  4. Android应用开发中的夜间模式实现(一)

    前言 在应用开发中会经常遇到要求实现夜间模式或者主题切换具体例子如下,我会先讲解第一种方法. 夜间模式 知乎 网易新闻 沪江开心词场 Pocket 主题切换 腾讯QQ 新浪微博 我今天主要是详述第一种 ...

  5. 【赛后补题】(HDU6223) Infinite Fraction Path {2017-ACM/ICPC Shenyang Onsite}

    场上第二条卡我队的题目. 题意与分析 按照题意能够生成一个有环的n个点图(每个点有个位数的权值).图上路过n个点显然能够生成一个n位数的序列.求一个最大序列. 这条题目显然是搜索,但是我队在场上(我负 ...

  6. 第二十二篇 正在表达式 re模块

    re模块****** 就本质而言,正则表达式时一种小型的,高度专业化的编程语言,在python里,它内嵌在python中,并通过re模块实现.正则表达式模式被编译成一系列的字节码.然后用C编写的匹配引 ...

  7. json与python解析

    1.json.dumps     将 Python 对象编码成 JSON 字符串   json.loads      将已编码的 JSON 字符串解码为 Python 对象 2.json.dump() ...

  8. 【Swift】日期比较函数 记录下 Comparing date in Swift

    Add this code to your project and comparing dates is easier than ever 扩展NSDATE //swift 3.0.2 extensi ...

  9. windows2008 R2 系统 安装wampserver提示“缺少msvcr110.dll文件”处理办法

    windows2008 R2 系统 安装wampserver提示“缺少msvcr110.dll文件”处理办法 原因分析: 因缺少Visual C++ Redistributable for Visua ...

  10. 【Python】python中的__dict__,__getattr__,__setattr__

    Python class 通过内置成员__dict__ 存储成员信息(字典) 首先用一个简单的例子看一下__dict__ 的用法 class A(): def __init__(self,ax,bx) ...