首先我们考虑,对于And 和 Or 操作,对于操作位上只有And 0 和 Or 1 是有效果的。
我们注意到如果区间内需要改动的操作位上的数字都相同,那么是可以区间取与以及区间取或的。
那其实可以维护出这个区间的$区间与x和区间或y$
我们考虑 $某一位上 x; xor ; y == 1 时$
必定是$x 那一位上 是0 ; y 那一位上是1$
因为显然 $如果x那一位上是1,那么y那一位上必然是1, y那一位上是0, x 那一位上必然是0$
那我们再考虑区间与的操作,我们令 $S = (1 << 31) - 1, 令val 表示需要与的数$
当 $(x ; xor ; y) ; and ; (S - val) == 0 的时候$
这个时候可以理解为在不需要与0的位置上,这个区间内都是1或者都是0,即这些不相关位对我们的区间取与操作不会有影响。
再考虑如何标记$lazy, 对And 和 Or 分别设置一个lazyA 和 lazyO $
$我们注意到,要取与的时候,把lazyA 一并与上, 并且把lazyO也要与上$
取或的时候只给$lazyO$取或就可以。
区间取或的操作分析同理。
再简陋的证明一下复杂度:
假设我们考虑要处理的一段区间不能进行区间处理,需要一位一位处理,但是我们这次处理之后这一段区间就可以区间处理了
再考虑,对于一段已经完好的区间,我们对它区间处理,它就会分成三段,但实际上这次的处理是$log的$
再考虑下一次处理,实际上两头又是好的,感觉又是$log$..
好吧 不口胡了,还是放官方的复杂度证明吧。。
https://csacademy.com/contest/round-70/task/and-or-max/solution
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 200010 5 int n, q, arr[N], S = (1 << 31) - 1; 6 7 struct SEG 8 { 9 struct node 10 { 11 int Max, A, O, lazyA, lazyO; 12 node() {} 13 node(int x) 14 { 15 Max = A = O = x; 16 lazyA = S; 17 lazyO = 0; 18 } 19 node operator + (const node &r) const 20 { 21 node res = node(0); 22 res.Max = max(Max, r.Max); 23 res.A = A & r.A; 24 res.O = O | r.O; 25 return res; 26 } 27 void add(int And, int Or) 28 { 29 Max = Max & And | Or; 30 A = A & And | Or; 31 O = O & And | Or; 32 lazyA = lazyA & And; 33 lazyO = lazyO & And | Or; 34 } 35 }a[N << 2]; 36 void build(int id, int l, int r) 37 { 38 if (l == r) 39 { 40 a[id] = node(arr[l]); 41 return; 42 } 43 int mid = (l + r) >> 1; 44 build(id << 1, l, mid); 45 build(id << 1 | 1, mid + 1, r); 46 a[id] = a[id << 1] + a[id << 1 | 1]; 47 } 48 void pushdown(int id) 49 { 50 if (a[id].lazyA != S || a[id].lazyO) 51 { 52 a[id << 1].add(a[id].lazyA, a[id].lazyO); 53 a[id << 1 | 1].add(a[id].lazyA, a[id].lazyO); 54 a[id].lazyA = S; 55 a[id].lazyO = 0; 56 } 57 } 58 void updateA(int id, int l, int r, int ql, int qr, int val) 59 { 60 if (l >= ql && r <= qr && !((a[id].A ^ a[id].O) & (S ^ val))) 61 { 62 a[id].add(val, 0); 63 return; 64 } 65 pushdown(id); 66 int mid = (l + r) >> 1; 67 if (ql <= mid) updateA(id << 1, l, mid, ql, qr, val); 68 if (qr > mid) updateA(id << 1 | 1, mid + 1, r, ql, qr, val); 69 a[id] = a[id << 1] + a[id << 1 | 1]; 70 } 71 void updateO(int id, int l, int r, int ql, int qr, int val) 72 { 73 if (l >= ql && r <= qr && !((a[id].A ^ a[id].O) & val)) 74 { 75 a[id].add(S, val); 76 return; 77 } 78 pushdown(id); 79 int mid = (l + r) >> 1; 80 if (ql <= mid) updateO(id << 1, l, mid, ql, qr, val); 81 if (qr > mid) updateO(id << 1 | 1, mid + 1, r, ql, qr, val); 82 a[id] = a[id << 1] + a[id << 1 | 1]; 83 } 84 int query(int id, int l, int r, int ql, int qr) 85 { 86 if (l >= ql && r <= qr) return a[id].Max; 87 pushdown(id); 88 int mid = (l + r) >> 1; 89 int res = 0; 90 if (ql <= mid) res = max(res, query(id << 1, l, mid, ql, qr)); 91 if (qr > mid) res = max(res, query(id << 1 | 1, mid + 1, r, ql, qr)); 92 a[id] = a[id << 1] + a[id << 1 | 1]; 93 return res; 94 } 95 }seg; 96 97 98 void Run() 99 { 100 while (scanf("%d%d", &n, &q) != EOF) 101 { 102 for (int i = 1; i <= n; ++i) scanf("%d", arr + i); 103 seg.build(1, 1, n); 104 for (int qq = 1, op, l, r, x; qq <= q; ++qq) 105 { 106 scanf("%d%d%d", &op, &l, &r); 107 if (op == 3) printf("%d ", seg.query(1, 1, n, l, r)); 108 else 109 { 110 scanf("%d", &x); 111 if (op == 1) seg.updateA(1, 1, n, l, r, x); 112 else seg.updateO(1, 1, n, l, r, x); 113 } 114 } 115 } 116 } 117 118 int main() 119 { 120 #ifdef LOCAL 121 freopen("Test.in", "r", stdin); 122 #endif 123 124 Run(); 125 return 0; 126 }