BZOJ 5312: 冒险

首先我们考虑,对于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\n", 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 }
View Code

猜你喜欢

转载自www.cnblogs.com/Dup4/p/9970887.html