在做着题之前, 可以先看一看这一题的简化版:STEP
反正就一个套路
题目传送门:序列操作
给定长度为 n n n的 01 01 01序列, 有五种操作
- 将下标 [ l , r ] [l,r] [l,r]内的数全改为 0 0 0
- 将下标 [ l , r ] [l,r] [l,r]内的数全改为 1 1 1
- 将下标 [ l , r ] [l,r] [l,r]内的数 0 0 0改为 1 1 1, 1 1 1 改为 0 0 0
- 求 ∑ i = l r a [ i ] \displaystyle\sum_{i=l}^{r}a[i] i=l∑ra[i]
- 求下标 [ l , r ] [l,r] [l,r]内最多有多少个连续的 1 1 1
太毒瘤了, 写得头皮发麻;
主要是细节太多了. 见代码
关于为何
p
u
s
h
d
o
w
n
pushdown
pushdown要放在前面, 因为若区间要先进行赋值再进行取反操作, 放后面的话赋值会覆盖掉取反.
// -----[今天不努力, 明天变垃圾]-----
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> P;
#define x first
#define y second
const int MAX_N = 2e5 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const double eps = 1e-6;
//
//
int n, m;
int a[MAX_N];
// sum维护区间总和, lazy维护区间赋值, rev维护区间翻转
// mx[0], lmx[0], rmx[0], 分别维护区间连续0的最大个数, 包括左端点的连续0的最大个数, 包括右端点的连续0的最大个数
// 1 同理
struct SegMentTree {
int l, r;
int sum, lazy, rev;
int mx[2], lmx[2], rmx[2];
} tree[MAX_N * 4];
#define l(x) tree[x].l
#define r(x) tree[x].r
#define sum(x) tree[x].sum
#define lazy(x) tree[x].lazy
#define rev(x) tree[x].rev
inline void push_up(int x) {
int llx = x * 2;
int rrx = x * 2 + 1;
sum(x) = sum(llx) + sum(rrx);
for(int i = 0; i <= 1; ++ i) {
tree[x].lmx[i] = tree[llx].lmx[i];
if(i == 1 && sum(llx) == r(llx) - l(llx) + 1) { // 左区间全为1
tree[x].lmx[i] += tree[rrx].lmx[i];
} else if(i == 0 && sum(llx) == 0) { // 左区间全为0
tree[x].lmx[i] += tree[rrx].lmx[i];
}
tree[x].rmx[i] = tree[rrx].rmx[i];
if(i == 1 && sum(rrx) == r(rrx) - l(rrx) + 1) { // 右区间全为1
tree[x].rmx[i] += tree[llx].rmx[i];
} else if(i == 0 && sum(rrx) == 0) { // 右区间全为0
tree[x].rmx[i] += tree[llx].rmx[i];
}
tree[x].mx[i] = tree[llx].rmx[i] + tree[rrx].lmx[i]; // 左右合并
tree[x].mx[i] = max(tree[x].mx[i], max(tree[llx].mx[i], tree[rrx].mx[i])); // 继承左右区间
}
}
inline void push_down(int x) {
int llx = x * 2;
int rrx = x * 2 + 1;
if(lazy(x) != -1) { // 有区间赋值时优先进行区间赋值 , 然后清除翻转标记
int k = lazy(x); // 延迟标记既代表了区间赋值, 也代表了整个区间的颜色
sum(llx) = k * (r(llx) - l(llx) + 1);
sum(rrx) = k * (r(rrx) - l(rrx) + 1);
lazy(llx) = lazy(rrx) = k;
rev(llx) = rev(rrx) = 0;
tree[llx].mx[k] = tree[llx].lmx[k] = tree[llx].rmx[k] = r(llx) - l(llx) + 1; // 区间内全为该种颜色
tree[llx].mx[k ^ 1] = tree[llx].lmx[k ^ 1] = tree[llx].rmx[k ^ 1] = 0; // 另一种颜色就消失了
tree[rrx].mx[k] = tree[rrx].lmx[k] = tree[rrx].rmx[k] = r(rrx) - l(rrx) + 1; // 同理
tree[rrx].mx[k ^ 1] = tree[rrx].lmx[k ^ 1] = tree[rrx].rmx[k ^ 1] = 0;
lazy(x) = -1;
rev(x) = 0; // 清除翻转标记
}
if(rev(x)) {
sum(llx) = r(llx) - l(llx) + 1 - sum(llx);
sum(rrx) = r(rrx) - l(rrx) + 1 - sum(rrx);
if(lazy(llx) != -1) lazy(llx) ^= 1;
else rev(llx) ^= 1;
if(lazy(rrx) != -1) lazy(rrx) ^= 1;
else rev(rrx) ^= 1;
// 翻转
swap(tree[llx].mx[0], tree[llx].mx[1]);
swap(tree[llx].lmx[0], tree[llx].lmx[1]);
swap(tree[llx].rmx[0], tree[llx].rmx[1]);
// 同理
swap(tree[rrx].mx[0], tree[rrx].mx[1]);
swap(tree[rrx].lmx[0], tree[rrx].lmx[1]);
swap(tree[rrx].rmx[0], tree[rrx].rmx[1]);
rev(x) = 0;
}
}
void build(int x, int l, int r) {
int llx = x * 2;
int rrx = x * 2 + 1;
l(x) = l; r(x) = r;
lazy(x) = -1;
if(l == r) {
sum(x) = a[l];
tree[x].mx[a[l]] = tree[x].lmx[a[l]] = tree[x].rmx[a[l]] = 1;
return;
}
int mid = (l + r) / 2;
build(llx, l, mid);
build(rrx, mid + 1, r);
push_up(x);
}
void update(int x, int l, int r, int val) {
int llx = x * 2;
int rrx = x * 2 + 1;
int mid = (r(x) + l(x)) / 2;
push_down(x);
if(l(x) == l && r(x) == r) {
if(val == 0 || val == 1) {
sum(x) = (r(x) - l(x) + 1) * val;
lazy(x) = val;
tree[x].mx[val] = tree[x].lmx[val] = tree[x].rmx[val] = r(x) - l(x) + 1;
tree[x].mx[val ^ 1] = tree[x].lmx[val ^ 1] = tree[x].rmx[val ^ 1] = 0;
} else if(val == 2) {
sum(x) = r(x) - l(x) + 1 - sum(x);
rev(x) ^= 1;
// 翻转
swap(tree[x].mx[0], tree[x].mx[1]);
swap(tree[x].lmx[0], tree[x].lmx[1]);
swap(tree[x].rmx[0], tree[x].rmx[1]);
}
return;
}
if(l >= mid + 1) update(rrx, l, r, val);
else if(r <= mid) update(llx, l, r, val);
else { update(llx, l, mid, val); update(rrx, mid + 1, r, val);}
push_up(x);
}
//bool operator < (const SegMentTree &a, const SegMentTree &b) {
// return a.mx[1] < b.mx[1];
//}
int query_sum(int x, int l, int r) {
int llx = x * 2;
int rrx = x * 2 + 1;
int mid = (r(x) + l(x)) / 2;
push_down(x);
if(l(x) == l && r(x) == r) {
return sum(x);
}
if(l >= mid + 1) return query_sum(rrx, l, r);
else if(r <= mid) return query_sum(llx, l, r);
else return query_sum(llx, l, mid) + query_sum(rrx, mid + 1, r);
}
SegMentTree query_max(int x, int l, int r) {
int llx = x * 2;
int rrx = x * 2 + 1;
int mid = (r(x) + l(x)) / 2;
push_down(x);
if(l(x) == l && r(x) == r) return tree[x];
if(l >= mid + 1) {
return query_max(rrx, l, r);
} else if(r <= mid) {
return query_max(llx, l, r);
} else {
SegMentTree res;
SegMentTree L = query_max(llx, l, mid), R = query_max(rrx, mid + 1, r);
res.sum = L.sum + R.sum;
for(int i = 0; i <= 1; ++ i) {
res.lmx[i] = L.lmx[i];
if(i == 1 && L.sum == L.r - L.l + 1) { // 左区间全为1
res.lmx[i] += R.lmx[i];
} else if(i == 0 && L.sum == 0) { // 左区间全为0
res.lmx[i] += R.lmx[i];
}
res.rmx[i] = R.rmx[i];
if(i == 1 && R.sum == R.r - R.l + 1) { // 右区间全为1
res.rmx[i] += L.rmx[i];
} else if(i == 0 && R.sum == 0) { // 右区间全为0
res.rmx[i] += L.rmx[i];
}
res.mx[i] = L.rmx[i] + R.lmx[i]; // 左右合并
res.mx[i] = max(res.mx[i], max(L.mx[i], R.mx[i])); // 继承左右区间
}
return res;
}
}
void solve() {
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; ++ i) scanf("%d", &a[i]);
build(1, 1, n);
while(m -- ) {
int op, l, r;
scanf("%d %d %d", &op, &l, &r);
++ l; ++ r;
if(op == 0 || op == 1 || op == 2) {
update(1, l, r, op);
} else if(op == 3) {
printf("%d\n", query_sum(1, l, r));
} else {
printf("%d\n", query_max(1, l, r).mx[1]);
}
}
}
signed main() {
// ios::sync_with_stdio(false);
// cin.tie(nullptr);
// cout.tie(nullptr);
int ZTY = 1;
//cin >> ZTY;
while(ZTY -- ) {
solve();
}
return 0;
}