zoukankan      html  css  js  c++  java
  • 【数据结构】分块

    单点修改,区间求和

    已验证:
    https://www.luogu.com.cn/problem/P3374 (单点修改,区间求和)

    rt[i]: i位置所属的块的序号
    va[i]: i位置的值
    lb[b]: 序号b的块的左边界的位置
    rb[b]: 序号b的块的左边界的位置
    sm[b]: 序号b的块的区间求和
    
    struct Block {
    
        static const int MAXN = 500000 + 5;
        static const int MAXB = 500000 + 5;
    
        int rt[MAXN];
        ll va[MAXN];
        int lb[MAXB];
        int rb[MAXB];
        ll sm[MAXB];
    
        void Add(int x, ll v) {
            va[x] += v;
            sm[rt[x]] += v;
        }
    
        ll Sum(int l, int r) {
            if(rt[l] == rt[r]) {
                ll res = 0LL;
                for(int i = l; i <= r; ++i)
                    res += va[i];
                return res;
            } else {
                ll res = 0LL;
                for(int i = l; i <= rb[rt[l]]; ++i)
                    res += va[i];
                for(int i = lb[rt[r]]; i <= r; ++i)
                    res += va[i];
                for(int b = rt[l] + 1; b <= rt[r] - 1; ++b)
                    res += sm[b];
                return res;
            }
        }
    
        void Init(int n) {
            int blk = (int)sqrt(n) + 1;
            int cntblk = (n + blk - 1) / blk;
            memset(va, 0LL, sizeof(va[0]) * (n + 1));
            memset(lb, INF, sizeof(lb[0]) * (cntblk + 1));
            memset(rb, -INF, sizeof(rb[0]) * (cntblk + 1));
            memset(sm, 0LL, sizeof(sm[0]) * (cntblk + 1));
            for(int i = 1; i <= n; ++i) {
                rt[i] = (i + blk - 1) / blk;
                lb[rt[i]] = min(lb[rt[i]], i);
                rb[rt[i]] = max(rb[rt[i]], i);
            }
        }
    
    } blk;
    

    区间修改,单点求值

    已验证:
    https://www.luogu.com.cn/problem/P3368 (区间修改,单点求值)

    rt[i]: i位置所属的块的序号
    va[i]: i位置的值
    lb[b]: 序号b的块的左边界的位置
    rb[b]: 序号b的块的左边界的位置
    lz[b]: 序号b的块的懒惰标记
    
    struct Block {
    
        static const int MAXN = 500000 + 5;
        static const int MAXB = 500000 + 5;
    
        int rt[MAXN];
        int va[MAXN];
        int lb[MAXB];
        int rb[MAXB];
        int lz[MAXB];
    
        void Add(int l, int r, int v) {
            if(rt[l] == rt[r]) {
                for(int i = l; i <= r; ++i)
                    va[i] += v;
            } else {
                for(int i = l; i <= rb[rt[l]]; ++i)
                    va[i] += v;
                for(int i = lb[rt[r]]; i <= r; ++i)
                    va[i] += v;
                for(int b = rt[l] + 1; b <= rt[r] - 1; ++b)
                    lz[b] += v;
            }
        }
    
        int Val(int x) {
            return va[x] + lz[rt[x]];
        }
    
        void Init(int n) {
            int blk = (int)sqrt(n) + 1;
            int cntblk = (n + blk - 1) / blk;
            memset(va, 0, sizeof(va[0]) * (n + 1));
            memset(lb, INF, sizeof(lb[0]) * (cntblk + 1));
            memset(rb, -INF, sizeof(rb[0]) * (cntblk + 1));
            memset(lz, 0, sizeof(lz[0]) * (cntblk + 1));
            for(int i = 1; i <= n; ++i) {
                rt[i] = (i + blk - 1) / blk;
                lb[rt[i]] = min(lb[rt[i]], i);
                rb[rt[i]] = max(rb[rt[i]], i);
            }
        }
    
    } blk;
    

    区间修改,区间求和

    区间修改多出一个懒惰标记。

    已验证:
    https://www.luogu.com.cn/problem/P3374 (单点修改,区间求和)
    https://www.luogu.com.cn/problem/P3368 (区间修改,单点求值)
    https://www.luogu.com.cn/problem/P3372 (区间修改,区间求和)

    rt[i]: i位置所属的块的序号
    va[i]: i位置的值
    lb[b]: 序号b的块的左边界的位置
    rb[b]: 序号b的块的左边界的位置
    sm[b]: 序号b的块的区间求和
    lz[b]: 序号b的块的懒惰标记
    
    struct Block {
    
        static const int MAXN = 500000 + 5;
        static const int MAXB = 500000 + 5;
    
        int rt[MAXN];
        ll va[MAXN];
        int lb[MAXB];
        int rb[MAXB];
        ll sm[MAXB];
        ll lz[MAXB];
    
        void Add(int l, int r, ll v) {
            if(rt[l] == rt[r]) {
                for(int i = l; i <= r; ++i)
                    va[i] += v;
                sm[rt[l]] += v * (r - l + 1);
            } else {
                for(int i = l; i <= rb[rt[l]]; ++i)
                    va[i] += v;
                sm[rt[l]] += v * (rb[rt[l]] - l + 1);
                for(int i = lb[rt[r]]; i <= r; ++i)
                    va[i] += v;
                sm[rt[r]] += v * (r - lb[rt[r]] + 1);
                for(int b = rt[l] + 1; b <= rt[r] - 1; ++b) {
                    sm[b] += v * (rb[b] - lb[b] + 1);
                    lz[b] += v;
                }
            }
        }
    
        ll Sum(int l, int r) {
            if(rt[l] == rt[r]) {
                ll res = 0LL;
                for(int i = l; i <= r; ++i) {
                    res += va[i];
                    res += lz[rt[i]];
                }
                return res;
            } else {
                ll res = 0LL;
                for(int i = l; i <= rb[rt[l]]; ++i)
                    res += va[i];
                res += lz[rt[l]] * (rb[rt[l]] - l + 1);
                for(int i = lb[rt[r]]; i <= r; ++i)
                    res += va[i];
                res += lz[rt[r]] * (r - lb[rt[r]] + 1);
                for(int b = rt[l] + 1; b <= rt[r] - 1; ++b)
                    res += sm[b];
                return res;
            }
        }
    
        void Init(int n) {
            int blk = (int)sqrt(n) + 1;
            int cntblk = (n + blk - 1) / blk;
            memset(va, 0LL, sizeof(va[0]) * (n + 1));
            memset(lb, INF, sizeof(lb[0]) * (cntblk + 1));
            memset(rb, -INF, sizeof(rb[0]) * (cntblk + 1));
            memset(sm, 0LL, sizeof(sm[0]) * (cntblk + 1));
            memset(lz, 0LL, sizeof(lz[0]) * (cntblk + 1));
            for(int i = 1; i <= n; ++i) {
                rt[i] = (i + blk - 1) / blk;
                lb[rt[i]] = min(lb[rt[i]], i);
                rb[rt[i]] = max(rb[rt[i]], i);
            }
        }
    
    } blk;
    
  • 相关阅读:
    java基础-基本的输入与输出
    Java基础-位运算符Bitwise Operators
    Java基础-字符串连接运算符String link operator
    Java基础-赋值运算符Assignment Operators与条件运算符Condition Operators
    Java基础-逻辑运算符Logic Operators
    Java基础-比较运算符Compare Operators
    Java基础-算术运算符(Arithmetic Operators)
    NGUI裁剪模型和粒子
    编辑器插件数据保存之Serializable
    using语法糖
  • 原文地址:https://www.cnblogs.com/purinliang/p/13672463.html
Copyright © 2011-2022 走看看