線段樹位運算區間更新(牛客東信杯j題)
阿新 • • 發佈:2019-01-05
思路:其實就是區間更新的時候,不是加減數了,而是用或運算,具體看程式碼
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio> using namespace std; typedef long long LL; const int maxn = 2e5 + 10; /* 用二進位制表示每個節點的值 加上一些牛逼的操作就能更新了,猛 舉個例子就很好懂了 如果一個區間的區間和是10(1010),並且區間長度是2,區間上每個元素或3(11),那麼最後的答案一定是14(1022) 注意1022的值是1*2^3+0*2^2+2*2^1+2*2^1; 也就是在更新的值的1位,更新成區間長度,0位不變,模擬一下二進位制運算就能明白 101+101=202=1010(202只是沒進位的1010)那麼101|11+101|11=222進位一下就是(1110=1022) 具體看程式碼吧,如果對lazy標記理解了,也能理解這個,只是更新方式不一樣 */ int val[maxn * 4][22]; int lazy[maxn * 4]; int n, m; LL ans; void pushup(int root) { for (int i = 0; i < 22; i++) { val[root][i] = val[root << 1][i] + val[root << 1 | 1][i]; } } void pushdown(int root, int len) { if (lazy[root]) { lazy[root << 1 | 1] |= lazy[root]; lazy[root << 1] |= lazy[root]; for (int i = 0; i < 22; i++) { if ((lazy[root] >> i) & 1) { val[root << 1][i] = len - (len >> 1); val[root << 1 | 1][i] = len>>1; } } lazy[root] = 0; } } void build(int root, int l, int r) { if (l == r) { int t; scanf("%d", &t); for (int i = 0; i < 22; i++) { val[root][i] = (t >> i) & 1; } return; } int mid = (l + r) >> 1; build(root << 1, l, mid); build(root << 1 | 1, mid + 1, r); pushup(root); } void update(int root, int L, int R, int l, int r, int V) { if (L <= l && r <= R) { lazy[root] |= V; for (int i = 0; i < 22; i++) { if ((V >> i) & 1) val[root][i] = r - l + 1; } return; } pushdown(root, r - l + 1); int mid = (l + r) >> 1; if (L <= mid) { update(root << 1, L, R, l, mid, V); } if (R > mid) { update(root << 1 | 1, L, R, mid + 1, r, V); } pushup(root); } void query(int root, int L, int R, int l, int r) { if (L <= l && r <= R) { for (int i = 0; i < 22; i++) { ans += ((LL)val[root][i] << i);//這步要注意,不能用int,會超資料範圍 } return; } pushdown(root, r - l + 1); int mid = (l + r) >> 1; if (L <= mid) { query(root << 1, L, R, l, mid); } if (R > mid) { query(root << 1 | 1, L, R, mid + 1, r); } pushup(root); } int main() { while (scanf("%d%d", &n, &m) != EOF) { memset(val, 0, sizeof(val)); memset(lazy, 0, sizeof(lazy)); build(1, 1, n); for (int i = 1; i <= m; i++) { char op[10]; scanf(" %s", op); if (op[0] == 'S') { int a, b; ans = 0; scanf("%d%d", &a, &b); query(1, a, b, 1, n); printf("%lld\n", ans); } else { int a, b, c; scanf("%d%d%d", &a, &b, &c); update(1, a, b, 1, n, c); } } } return 0; }