• 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
    ", query(u, v));
    109     }
    110     return 0;
    111 }
  • 相关阅读:
    009-Python-面向对象
    008-Python-模块
    007-Python函数-装饰器
    006-Python函数
    005-Python字典
    003-python列表
    PyCharm之python书写规范--消去提示波浪线
    001-python基础
    Java基础总结(一)
    High ASCII字符从bat文件到dos控制台的转化问题
  • 原文地址:https://www.cnblogs.com/cminus/p/8571202.html
Copyright © 2020-2023  润新知