题面

传送门

"奋战三星期,造台计算机"。小G响应号召,花了三小时造了台普通计算姬。普通计算姬比普通计算机要厉害一些

。普通计算机能计算数列区间和,而普通计算姬能计算树中子树和。更具体地,小G的计算姬可以解决这么个问题

:给定一棵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]

尽管计算姬可以很快完成这个问题,可是小G并不知道它的答案是否正确,你能帮助他吗?

分析

刚看到这题想到树剖套线段树的做法,但是时间复杂度太大,无法接受。既然用log级的数据结构无法维护,很容易想到分块。按节点编号分块,每个块维护sum[l]+sum[l+1]+...+sum[r],[l,r]为块边界

这道题的突破口是考虑每个节点的贡献

对于每个节点u来说,它的值被改为v,只会影响u的祖先节点的子树和。

因此可以分块预处理\(f[i][j]\)表示第i个节点有多少个祖先节点在第j个块里面。dfs的时候维护一个数组cnt[i]存储当前搜索树中有多少个节点在第i块中,递归到某个节点x时cnt[x]++,回溯时cnt[x]--,这样\(f[x][i]=cnt[i]\)

那么如果某个节点x的值增加了d,我们就遍历每个块i,每个块i的和增加\(f[x][i]\times d\)

查询的时候整块可以直接加上和。对于不完整的部分,直接查询每个节点的子树和再相加,用dfs序+树状数组的方法维护。树状数组的第i个位置存储第i个节点的值,查询子树和的时候利用dfs序可以\(O(\log n)\)的时间内查询出第i个节点的子树和

坑点:

此题不能用树状数组,会被卡常。记得开unsigned long long,否则会爆

代码

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<cmath>
  5. #define maxn 100005
  6. #define maxb 505
  7. #define ll unsigned long long
  8. using namespace std;
  9. int n,m;
  10. struct BIT {
  11. ll t[maxn];
  12. inline ll lowbit(int x){
  13. return x&(-x);
  14. }
  15. void update(int x,ll v){
  16. while(x<=n){
  17. t[x]+=v;
  18. x+=lowbit(x);
  19. }
  20. }
  21. ll sum(int x){
  22. ll ans=0;
  23. while(x>0){
  24. ans+=t[x];
  25. x-=lowbit(x);
  26. }
  27. return ans;
  28. }
  29. ll query(int l,int r){
  30. return sum(r)-sum(l-1);
  31. }
  32. }T;
  33. struct edge {
  34. int from;
  35. int to;
  36. int next;
  37. } E[maxn<<1];
  38. int head[maxn];
  39. int esz=1;
  40. void add_edge(int u,int v) {
  41. esz++;
  42. E[esz].from=u;
  43. E[esz].to=v;
  44. E[esz].next=head[u];
  45. head[u]=esz;
  46. }
  47. ll a[maxn];
  48. int bsz,bcnt;//块大小,块个数
  49. inline int lb(int id) {
  50. return (id-1)*bsz+1;
  51. }
  52. inline int rb(int id) {
  53. return (id*bsz>n)?n:id*bsz;
  54. }
  55. int cnt[maxb];//cnt[i]存第i个块内有多少个当前搜索树中的节点
  56. int f[maxn][maxb]; //f[i][j]存第i个块内有多少个j的祖先节点
  57. ll sum[maxn];//整块的和
  58. int id[maxn];
  59. int dfnl[maxn],dfnr[maxn];
  60. int tim=0;
  61. void dfs(int x,int fa) {
  62. dfnl[x]=++tim;
  63. cnt[id[x]]++;
  64. for(int i=1; i<=bcnt; i++) {
  65. f[x][i]=cnt[i];
  66. }
  67. for(int i=head[x]; i; i=E[i].next) {
  68. int y=E[i].to;
  69. if(y!=fa) {
  70. dfs(y,x);
  71. }
  72. }
  73. dfnr[x]=tim;
  74. cnt[id[x]]--;
  75. }
  76. void change(int u,ll v){
  77. ll pre=T.query(dfnl[u],dfnl[u]);
  78. T.update(dfnl[u],v-pre);
  79. for(int i=1;i<=bcnt;i++){
  80. sum[i]+=(ll)f[u][i]*(v-pre);
  81. }
  82. }
  83. ll ask(int l,int r){
  84. ll ans=0;
  85. for(int i=l;i<=min(r,rb(id[l]));i++){
  86. ans+=T.query(dfnl[i],dfnr[i]);
  87. }
  88. for(int i=id[l]+1;i<id[r];i++){
  89. ans+=sum[i];
  90. }
  91. if(id[l]!=id[r]){
  92. for(int i=lb(id[r]);i<=r;i++){
  93. ans+=T.query(dfnl[i],dfnr[i]);
  94. }
  95. }
  96. return ans;
  97. }
  98. int main() {
  99. int op,u,v,l,r,root;
  100. ll k;
  101. scanf("%d %d",&n,&m);
  102. for(int i=1;i<=n;i++) scanf("%llu",&a[i]);
  103. for(int i=1;i<=n;i++){
  104. scanf("%d %d",&u,&v);
  105. if(u==0) root=v;
  106. else{
  107. add_edge(u,v);
  108. add_edge(v,u);
  109. }
  110. }
  111. bsz=sqrt(n);
  112. bcnt=1;
  113. for(int i=1;i<=n;i++){
  114. id[i]=bcnt;
  115. if(i%bsz==0) bcnt++;
  116. }
  117. dfs(root,0);
  118. for(int i=1;i<=n;i++){
  119. T.update(dfnl[i],a[i]);
  120. }
  121. for(int i=1;i<=n;i++){
  122. sum[id[i]]+=T.query(dfnl[i],dfnr[i]);
  123. }
  124. for(int i=1;i<=m;i++){
  125. scanf("%d",&op);
  126. if(op==1){
  127. scanf("%d",&u);
  128. scanf("%llu",&k);
  129. change(u,k);
  130. }else{
  131. scanf("%d %d",&l,&r);
  132. printf("%llu\n",ask(l,r));
  133. }
  134. }
  135. }

BZOJ 4765(分块+树状数组)的更多相关文章

  1. 【BZOJ 3295】动态逆序对 - 分块+树状数组

    题目描述 给定一个1~n的序列,然后m次删除元素,每次删除之前询问逆序对的个数. 分析:分块+树状数组 (PS:本题的CDQ分治解法见下一篇) 首先将序列分成T块,每一块开一个树状数组,并且先把最初的 ...

  2. 【bzoj2141】排队 分块+树状数组

    题目描述 排排坐,吃果果,生果甜嗦嗦,大家笑呵呵.你一个,我一个,大的分给你,小的留给我,吃完果果唱支歌,大家乐和和.红星幼儿园的小朋友们排起了长长地队伍,准备吃果果.不过因为小朋友们的身高有所区别, ...

  3. 【bzoj3744】Gty的妹子序列 分块+树状数组+主席树

    题目描述 我早已习惯你不在身边, 人间四月天 寂寞断了弦. 回望身后蓝天, 跟再见说再见…… 某天,蒟蒻Autumn发现了从 Gty的妹子树(bzoj3720) 上掉落下来了许多妹子,他发现 她们排成 ...

  4. 【分块+树状数组】codechef November Challenge 2014 .Chef and Churu

    https://www.codechef.com/problems/FNCS [题意] [思路] 把n个函数分成√n块,预处理出每块中各个点(n个)被块中函数(√n个)覆盖的次数 查询时求前缀和,对于 ...

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

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

  6. Bzoj 3295: [Cqoi2011]动态逆序对 分块,树状数组,逆序对

    3295: [Cqoi2011]动态逆序对 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2886  Solved: 924[Submit][Stat ...

  7. BZOJ 3744: Gty的妹子序列 【分块 + 树状数组 + 主席树】

    任意门:https://www.lydsy.com/JudgeOnline/problem.php?id=3744 3744: Gty的妹子序列 Time Limit: 20 Sec  Memory ...

  8. BZOJ 3744 Gty的妹子序列 (分块+树状数组+主席树)

    题面传送门 题目大意:给你一个序列,多次询问,每次取出一段连续的子序列$[l,r]$,询问这段子序列的逆序对个数,强制在线 很熟悉的分块套路啊,和很多可持久化01Trie的题目类似,用分块预处理出贡献 ...

  9. BZOJ 2141 排队(分块+树状数组)

    题意 第一行为一个正整数n,表示小朋友的数量:第二行包含n个由空格分隔的正整数h1,h2,…,hn,依次表示初始队列中小朋友的身高:第三行为一个正整数m,表示交换操作的次数:以下m行每行包含两个正整数 ...

随机推荐

  1. JS 数组 学习笔记

    什么是数组 数组(array)是按次序排列的一组值.每个值的位置都有编号(从0开始),整个数组用方括号表示.本质上数组属于一种特殊的,由Array构造出来的对象,typeof运算符返回数组的类型是 o ...

  2. Django学习记录--~Biubiubiu

    Day One Django常用命令 1.创建Django网站框架 django-admin startproject mysite # mysite为定义的项目文件夹名称 2.超级用户创建 py m ...

  3. smbumount - 为普通用户卸载smb文件系统

    总览 smbumount 装载点 描述 普通用户使用这个程序可以卸载smb文件系统.它在工作时会suid到root身份,并且向普通linux用户提供了对资源更多的控制能力.在suid方面,它拥有足够的 ...

  4. 02.LNMP架构-MySQL源码包编译部署详细步骤

    操作系统:CentOS_Server_7.5_x64_1804.iso 部署组件:Cmake+Boost+MySQL 操作步骤: 一.安装依赖组件 [root@localhost ~]# yum -y ...

  5. CS184.1X 计算机图形学导论 HomeWork1

    最容易填写的函数就是left.输入为旋转的角度,当前的eye与up这两个三维向量 void Transform::left(float degrees, vec3& eye, vec3& ...

  6. Gene Ontology (GO) 注释

    Gene Ontology (GO) 注释  Posted on 2017-06-11 |  In 生信 相似的基因在不同物种中,其功能往往保守的.显然,需要一个统一的术语用于描述这些跨物种的同源基因 ...

  7. mobx学习笔记03——mobx基础语法(decorator修饰器)

    在声明阶段实现类与类成员注解的一种语法. function log(target){ const desc = Object.getOwnPropertyDescriotors(target.prot ...

  8. MySQL提示:too many connections

    1.首先查询最大连接数 show variables like '%max_connections%'; 2.检查当前的连接情况: show processlist; 3.批量kill当前的连接: 通 ...

  9. 报数问题:有n个人围成一圈,顺序排号。从第一个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号的那位

    n = int(input("请输入人数:")) list_p = list(range(1,n+1)) #将所有人放在一个数字里面 count = 0 #设置一个变量,用户计算报 ...

  10. mybatis源码分析之01环境搭建

    直接使用maven搭建一个mybatis的运行环境 1. pom.xml <?xml version="1.0" encoding="UTF-8"?> ...