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;
    }
    
  • 相关阅读:
    C++多态
    C++和C#实现剪切板数据交互
    通过CLR API实现C++调用C#代码交互
    COM方式实现C++调用C#代码的一些总结
    输入LPCWSTR类型字符串
    取得COM对象的UUID并以string输出
    springmvc xml文件配置中使用系统环境变量
    SpringMVC,SpringBoot上传文件简洁代码
    c语言实行泛型hashmap
    java使用nio(Paths,Files)遍历文件目录,转成java.io.File
  • 原文地址:https://www.cnblogs.com/yywxdgy/p/13706449.html
Copyright © 2011-2022 走看看