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 }

 

posted @ 2018-03-15 00:57  cminus  阅读(167)  评论(0编辑  收藏  举报