最近一直在刷分块啊

似乎感觉分块和BIT是超级棒的搭档啊

这道题首先用dfs预处理一下

得到每一个sum值

此时查询是O(1)的  (前缀和乱搞什么的

但是修改需要O(n) (需要修改该节点所有祖先的sum

复杂度就爆了呀

此时考虑分块优化

似乎弹飞绵羊也是这样思考得出分块做法的

首先分成 √n 块

sum[i]记录第i块的sum和

中间的块直接用sum数组处理  两边用树状数组暴力求

这样查询就是O(√n)的 (其实有一些常数的...  就当是 √n 好了)

修改的话在dfs时用f[i][j]表示第j个点对于第i块的贡献 (需要算几次什么的

然后直接修改块就好了  复杂度也是O (√n) 的

下面是代码

 #include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
using namespace std;
#define isdigit(x) (x >= '0' && x <= '9')
#define lowbit(x) (x & (-x))
typedef unsigned long long ll;
const int N = 1e5 + ;
const int M = ; int n, root, cnt, sz, tot;
int d[N], b[N], f[M][N], ct[N], L[N], p[N];
ll s[N], c[N];
vector < int > E[N]; inline void read(int &ans) {
ans = ;
register int res = ;
static char buf = getchar();
for (; !isdigit(buf); buf = getchar())
if (buf == '-') res = -;
for (; isdigit(buf); buf = getchar())
ans = ans * + buf - '';
ans *= res;
} inline void addEdge(int u ,int v) {
E[u].push_back(v);
E[v].push_back(u);
} inline void add(int x, ll v) {
while (x <= n) {
c[x] += v;
x += lowbit(x);
}
} inline ll query(int x) {
ll ans = ;
while (x > ) {
ans += c[x];
x -= lowbit(x);
}
return ans;
} ll dfs(int x, int fa) {
ll sum = d[x]; p[x] = ++tot;
ct[b[x]]++; add(tot, d[x]);
for (int i = ; i <= cnt; i++) f[i][x] += ct[i];
for (int i = ; i < E[x].size(); i++) {
int u = E[x][i];
if (u == fa) continue;
sum += dfs(u, x);
}
ct[b[x]]--; L[x] = tot;
s[b[x]] += sum;
return sum;
} inline void modify(int u, int v) {
add(p[u], v - d[u]);
for (int i = ; i <= cnt; i++)
s[i] += (v - d[u]) * 1ll * f[i][u];
d[u] = v;
} inline ll query(int l ,int r) {
ll ans = ;
if (b[l] == b[r]) {
for (int i = l; i <= r; i++)
ans += query(L[i]) - query(p[i] - );
return ans;
}
for (int i = b[l] + ; i < b[r]; i++)
ans += s[i];
for (int i = l; i <= b[l] * sz; i++)
ans += query(L[i]) - query(p[i] - );
for (int i = (b[r] - ) * sz + ; i <= r; i++)
ans += query(L[i]) - query(p[i] - );
return ans;
} int main() {
int m;
read(n); read(m);
sz = sqrt(n);
for (int i = ; i <= n; i++) {
read(d[i]);
b[i] = (i - ) / sz + ;
}
cnt = b[n];
for (int i = ; i <= n; i++) {
int u, v;
read(u); read(v);
if (!u) root = v;
else addEdge(u, v);
}
dfs(root, );
while (m--) {
int op, u, v;
read(op); read(u); read(v);
if (op == )
modify(u, v);
else
printf("%llu\n", query(u, v));
}
return ;
}

最新文章

  1. hibernate笔记--组件映射方法
  2. VUE 入门基础(1)
  3. &lt;转&gt;C++11标准后的C++阅读书目
  4. Android 的系统架构
  5. MySQL数据库学习笔记(一)----MySQL 5.6.21的安装和配置(setup版)
  6. JDBC的URL设置allowMultiQueries的原因
  7. ofbiz进阶之框架配置文件指导
  8. C++ 文件操作(CFile类)
  9. linux系统巡检脚本shell实例
  10. usaco 1.2.1(指针技巧)
  11. Go学习笔记(一)Let&#39;s 干
  12. PE格式第八讲,TLS表(线程局部存储)
  13. 【安卓中的缓存策略系列】安卓缓存策略之综合应用ImageLoader实现照片墙的效果
  14. [Swift]LeetCode491. 递增子序列 | Increasing Subsequences
  15. lightoj1197 素数双筛,可以参考poj的那题双筛
  16. OpenCV-Python入门教程4-颜色空间转换
  17. ABC2
  18. 微信小程序学习之for循环
  19. .net 开源组件推荐 之 StackExchange
  20. Spring之注入复杂类型属性

热门文章

  1. 【巨杉数据库SequoiaDB】巨杉数据库 v5.0 Beta版 正式发布
  2. CTF伪协议+preg_replace()函数的代码执行
  3. Secondary NameNode:它究竟有什么作用?
  4. css 字体旋转
  5. CentOS虚拟机挂载U盘
  6. Python类的特殊成员方法
  7. Windows10通过命令行导出笔记本电池使用信息
  8. 在Visual Studio中将dll以资源的形式嵌入exe中
  9. php 公众号开发
  10. flutter loading