zoukankan      html  css  js  c++  java
  • QUERIES

    (mathcal{Description:})

    给定一个长度为 n 的序列 (a_1, a_2, a_3, ..., a_n), 每个数大小不超过 1000;

    有 m 次操作,每次操作改变一个数的值,或求一段区间 [l, r] 的所有子区间的异或和之和。

    多组数据。 每个操作第一个数是 opt

    • 当 opt 为 1 时,读入 pos, val,表示修改第 pos 个数的值为 val。
    • 当 opt 为 2 时,读入 l, r, 表示询问 (sum_{l leq i leq j leq r} igoplus_{i leq k leq j} a_k)

    (mathcal{Solution:})

    (mathbb{Summary:})

    线段树分治入门题。因为直接做看起来没什么思路,数的范围又在 1000 以内,考虑拆位算贡献。

    ( ext{Segmentree}_i) 表示序列上数的第 i 位所构建的线段树。

    对于线段树上每个点:

    • 定义 sum 为区间异或和。

    • l0、l1 表示区间内 从左到右连续的、异或和分别为 0、1 的子序列 个数。

      r0、r1 表示区间内 从右到左连续的、异或和分别为 0、1 的子序列 个数。

    • s0、s1 表示区间内 异或和分别为 0、1 的子序列 个数。

    转移也十分显然:

    [egin{aligned} & sum_p = sum_{ls} oplus sum_{rs} \ & l_{0, p} = l_{0,ls} + l_{sum_{ls}, rs}, l_{1, p} = l_{1, ls} + l_{sum_{ls} oplus 1, rs} \ & r_{0, p} = r_{0,rs} + r_{sum_{rs}, ls}, r_{1, p} = r_{1, rs} + r_{sum_{rs} oplus 1, ls} \ & s_{0, p} = s_{0, ls} + s_{0, rs} + l_{0, rs} r_{0, ls} + l_{1, rs} r_{1, ls} \ & s_{1, p} = s_{1, ls} + s_{1, rs} + l_{1, rs} r_{0, ls} + l_{0, rs} r_{1, ls} end{aligned} ]

    根据异或运算的规律 相同则 0, 不同为 1,可以很好理解上述转移式。

    (mathbb{Detail:})

    • 空间比较紧,注意到 (2^{10} = 1024 > 1000),所以线段树理论开 9 棵即可。

    • 注意模数为 4001

    • 也许可以定义一个类,这样构造、修改、查询都方便。

    (mathbb{Code:})

    #include <bits/stdc++.h>
    #define Rep(i, a, b) for (int i = (a), bb = (b); i <= bb; ++i)
    const int N = 1e5 + 5, mod = 4001;
    using namespace std;
    int n, m, a[N], t, ans;
    char BB[1 << 15], *S = BB, *T = BB;
    #define getchar() (S == T && (T = (S = BB) + fread(BB, 1, 1 << 15, stdin), S == T) ? EOF : *S++)
    inline int read() { 
        int s = 0; char c = getchar(); for (; !isdigit(c); c = getchar()); 
        for (; isdigit(c); c = getchar()) s = (s << 3) + (s << 1) + c - 48; return s; 
    }
    template <class K> inline void write(K x) { 
        (x > 9 ? write(x / 10) : void()); 
        return putchar(x % 10 + 48), void(); 
    }
    inline int add(int a, int b) { return a + b >= mod ? a + b - mod : a + b; } 
    inline void Add(int &a, int b) { return a = add(a, b), void(); }
    inline int mul(int a, int b) { return 1LL * a * b % mod; } 
    inline void Mul(int &a, int b) { return a = mul(a, b), void(); }
    struct Se_P { 
        int sum, s[2], l[2], r[2]; 
        inline void clear(){sum = 0; Rep(i, 0, 1) s[i] = l[i] = r[i] = 0;}
    } Void;
    struct Segmentree { 
        Se_P t[N << 2], s; int tmp;
        #define sum(p) t[p].sum
        #define ls (p << 1)
        #define rs (ls | 1)
        #define mid ((x + y) >> 1)
        #define Ls ls, x, mid
        #define Rs rs, mid + 1, y
        inline Se_P Spread(Se_P l, Se_P r) { s.clear();
            s.s[0] = add(add(add(l.s[0], r.s[0]), mul(l.r[0], r.l[0])), mul(l.r[1], r.l[1]));
            s.s[1] = add(add(add(l.s[1], r.s[1]), mul(l.r[0], r.l[1])), mul(l.r[1], r.l[0]));
            
            if (l.sum == 0) s.l[0] = l.l[0] + r.l[0], s.l[1] = l.l[1] + r.l[1];
            else s.l[0] = l.l[0] + r.l[1], s.l[1] = l.l[1] + r.l[0];
                                            
            if (r.sum == 0) s.r[0] = r.r[0] + l.r[0], s.r[1] = r.r[1] + l.r[1];
            else s.r[0] = r.r[0] + l.r[1], s.r[1] = r.r[1] + l.r[0];
                                            
            s.sum = l.sum ^ r.sum;
            return s;
        }
        inline void Push(int p) { return t[p] = Spread(t[ls], t[rs]), void(); }
        inline void Build(int p, int x, int y, int op) { 
            t[p].clear();
            if (x == y) { 
                tmp = (a[x] & (1 << op)) ? 1 : 0; 
                return t[p].l[tmp] = t[p].r[tmp] = t[p].s[tmp] = 1, sum(p) = tmp, void(); 
            }
            return Build(Ls, op), Build(Rs, op), Push(p);
        }
        inline void Modify(int p, int x, int y, int pos, int v) {
            if (x == y) return t[p].clear(), t[p].l[v] = t[p].r[v] = t[p].s[v] = 1, sum(p) = v, void();
            (pos <= mid ? Modify(Ls, pos, v) : Modify(Rs, pos, v)), Push(p);
        }
        inline Se_P Ask(int p, int x, int y, int l, int r) {
            if (l > r || x > y || x > r || l > y) return Void;
            if (l <= x && y <= r) return t[p];
            return Spread(Ask(Ls, l, r), Ask(Rs, l, r));
        }
    } Se[10];
    int main(void) {
        n = read(), m = read(), Void.clear();
        Rep(i, 1, n) a[i] = read();
        Rep(i, 0, 9) Se[i].Build(1, 1, n, i);
        Rep(i, 1, m) {
            int opt = read(), x = read(), y = read();
            if (opt == 1) { 
                Rep(i, 0, 9) Se[i].Modify(1, 1, n, x, (y & (1 << i)) ? 1 : 0); 
            }
            if (opt == 2) { 
                t = 1, ans = 0;
                Rep(i, 0, 9) Add(ans, mul(Se[i].Ask(1, 1, n, x, y).s[1], t)), Mul(t, 2);
                write(ans), putchar(10);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    php多态
    ssl certificate problem: self signed certificate in certificate chain
    test plugin
    open specific port on ubuntu
    junit vs testng
    jersey rest service
    toast master
    use curl to test java webservice
    update folder access
    elk
  • 原文地址:https://www.cnblogs.com/yywxdgy/p/13706449.html
Copyright © 2011-2022 走看看