linux--系統管理--使用者和使用者組管理
阿新 • • 發佈:2020-09-21
\(\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} \bigoplus_{i \leq k \leq j} a_k\)
\(\mathcal{Solution:}\)
\(\mathbb{Summary:}\)
線段樹分治入門題。因為直接做看起來沒什麼思路,數的範圍又在 1000 以內,考慮拆位算貢獻。
\(\text{Segmentree}_i\) 表示序列上數的第 i 位所構建的線段樹。
對於線段樹上每個點:
-
定義 sum 為區間異或和。
-
l0、l1 表示區間內 從左到右連續的、異或和分別為 0、1 的子序列 個數。
r0、r1 表示區間內 從右到左連續的、異或和分別為 0、1 的子序列 個數。
-
s0、s1 表示區間內 異或和分別為 0、1 的子序列 個數。
轉移也十分顯然:
\[\begin{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; }