bzoj4765: 普通计算姬 (分块 && BIT)
最近一直在刷分块啊
似乎感觉分块和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) 的
下面是代码
1 #include <cstdio> 2 #include <cmath> 3 #include <algorithm> 4 #include <vector> 5 using namespace std; 6 #define isdigit(x) (x >= '0' && x <= '9') 7 #define lowbit(x) (x & (-x)) 8 typedef unsigned long long ll; 9 const int N = 1e5 + 10; 10 const int M = 350; 11 12 int n, root, cnt, sz, tot; 13 int d[N], b[N], f[M][N], ct[N], L[N], p[N]; 14 ll s[N], c[N]; 15 vector < int > E[N]; 16 17 inline void read(int &ans) { 18 ans = 0; 19 register int res = 1; 20 static char buf = getchar(); 21 for (; !isdigit(buf); buf = getchar()) 22 if (buf == '-') res = -1; 23 for (; isdigit(buf); buf = getchar()) 24 ans = ans * 10 + buf - '0'; 25 ans *= res; 26 } 27 28 inline void addEdge(int u ,int v) { 29 E[u].push_back(v); 30 E[v].push_back(u); 31 } 32 33 inline void add(int x, ll v) { 34 while (x <= n) { 35 c[x] += v; 36 x += lowbit(x); 37 } 38 } 39 40 inline ll query(int x) { 41 ll ans = 0; 42 while (x > 0) { 43 ans += c[x]; 44 x -= lowbit(x); 45 } 46 return ans; 47 } 48 49 ll dfs(int x, int fa) { 50 ll sum = d[x]; p[x] = ++tot; 51 ct[b[x]]++; add(tot, d[x]); 52 for (int i = 1; i <= cnt; i++) f[i][x] += ct[i]; 53 for (int i = 0; i < E[x].size(); i++) { 54 int u = E[x][i]; 55 if (u == fa) continue; 56 sum += dfs(u, x); 57 } 58 ct[b[x]]--; L[x] = tot; 59 s[b[x]] += sum; 60 return sum; 61 } 62 63 inline void modify(int u, int v) { 64 add(p[u], v - d[u]); 65 for (int i = 1; i <= cnt; i++) 66 s[i] += (v - d[u]) * 1ll * f[i][u]; 67 d[u] = v; 68 } 69 70 inline ll query(int l ,int r) { 71 ll ans = 0; 72 if (b[l] == b[r]) { 73 for (int i = l; i <= r; i++) 74 ans += query(L[i]) - query(p[i] - 1); 75 return ans; 76 } 77 for (int i = b[l] + 1; i < b[r]; i++) 78 ans += s[i]; 79 for (int i = l; i <= b[l] * sz; i++) 80 ans += query(L[i]) - query(p[i] - 1); 81 for (int i = (b[r] - 1) * sz + 1; i <= r; i++) 82 ans += query(L[i]) - query(p[i] - 1); 83 return ans; 84 } 85 86 int main() { 87 int m; 88 read(n); read(m); 89 sz = sqrt(n); 90 for (int i = 1; i <= n; i++) { 91 read(d[i]); 92 b[i] = (i - 1) / sz + 1; 93 } 94 cnt = b[n]; 95 for (int i = 1; i <= n; i++) { 96 int u, v; 97 read(u); read(v); 98 if (!u) root = v; 99 else addEdge(u, v); 100 } 101 dfs(root, 0); 102 while (m--) { 103 int op, u, v; 104 read(op); read(u); read(v); 105 if (op == 1) 106 modify(u, v); 107 else 108 printf("%llu\n", query(u, v)); 109 } 110 return 0; 111 }