传送门
原题是SCOI2010序列操作。HDU上的版本是其加强版(多组数据),还要初始化。我是不会对你说我不加初始化然后在HDU上WA了无数次的
没错,这就是一道线段树区间合并和区间修改的综合模板神题。
线段树区间合并不会的童鞋们请参考这。
接下来讲讲如何实现这几种操作:
- 0 a b change all characters into ‘0’s in [a , b]
意为把区间 中的所有数改成0,就是板子里的 ,略过。 - 1 a b change all characters into ‘1’s in [a , b]
意为把区间 中的所有数改成1,还是板子里的 ,略过。 - 2 a b change all ‘0’s into ‘1’s and change all ‘1’s into ‘0’s in [a, b]
意为把区间 中的0和1对调,由于存在2操作和3操作,使得我们像板子里一样只维护关于1的信息变得不可行,所以我们还要维护关于0的信息,所以这题就特别恶心。中还要加入对0的维护。 的具体写法和一般线段树几乎完全相同。 - 3 a b output the number of ‘1’s in [a, b]
意为统计区间 中1的个数,很显然,等效于求区间 中数的总和,对策也很好想,像一般线段树一样维护一个 统计区间 的总和, 统计。 - 4 a b output the length of the longest continuous ‘1’ string in [a , b]
意为统计区间 中最长的连续的1的长度,相当于板子里的 ,略过。
经过对几个操作的分析,我们可以发现这道题其实就是几个操作混合了一下,本身并算不上难,细节比较多,错的话调试非常麻烦而已。
说到细节,我就来说明一下几个重要的细节:
- 中不仅要有对1的维护,也要包含对0的维护和对区间和的维护。
- 中要将所有的信息重置,1的信息和0的信息要对应地对调。假如如见单一, 也要取反,区间和要修改。
- 中一定要先翻转然后覆盖。
- 进行值覆盖的时候要将 标记清除。
- 最后一点,也是很坑的一点,不要忘了初始化。。。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define max(x, y) ((x) > (y) ? (x) : (y))
#define min(x, y) ((x) < (y) ? (x) : (y))
using std::swap;
int a[100005];
struct SegTree {
#define lc(o) o << 1
#define rc(o) o << 1 | 1
#define mid ((l + r) >> 1)
#define MS(array) memset(array, 0, sizeof array)
struct Ans {
int ls, rs, s;
Ans(int ls, int rs, int s) : ls(ls), rs(rs), s(s) {}
};
static const int MAXSIZE = 100000 + 5;
int lsum1[MAXSIZE << 2], rsum1[MAXSIZE << 2], sum1[MAXSIZE << 2], color[MAXSIZE << 2];
int lsum0[MAXSIZE << 2], rsum0[MAXSIZE << 2], sum0[MAXSIZE << 2], sum[MAXSIZE << 2];
bool reversed[MAXSIZE << 2];
void clear() { //初始化
MS(lsum1); MS(rsum1); MS(sum1); MS(color);
MS(lsum0); MS(rsum0); MS(sum0); MS(sum);
MS(reversed);
}
void creat(int o, int l, int r, int value) { //值覆盖
color[o] = value; reversed[o] = false;
lsum1[o] = rsum1[o] = sum1[o] = sum[o] = value ? r - l + 1 : 0;
lsum0[o] = rsum0[o] = sum0[o] = value ? 0 : r - l + 1;
}
void cover(int o, int l, int r) { //翻转覆盖
reversed[o] ^= true;
swap(lsum1[o], lsum0[o]);
swap(rsum1[o], rsum0[o]);
swap(sum1[o], sum0[o]);
if (color[o] != -1) color[o] ^= 1;
sum[o] = (r - l + 1) - sum[o];
}
void pushdown(int o, int l, int r) { //pushdown()
if (reversed[o]) { //先判断翻转覆盖
cover(lc(o), l, mid);
cover(rc(o), mid + 1, r);
reversed[o] = false;
}
if (color[o] != -1) {
creat(lc(o), l, mid, color[o]);
creat(rc(o), mid + 1, r, color[o]);
}
}
void pushup(int o) { //繁琐的pushup()
lsum1[o] = color[lc(o)] == 1 ? lsum1[lc(o)] + lsum1[rc(o)] : lsum1[lc(o)];
rsum1[o] = color[rc(o)] == 1 ? rsum1[lc(o)] + rsum1[rc(o)] : rsum1[rc(o)];
sum1[o] = max(rsum1[lc(o)] + lsum1[rc(o)], max(sum1[lc(o)], sum1[rc(o)]));
lsum0[o] = color[lc(o)] == 0 ? lsum0[lc(o)] + lsum0[rc(o)] : lsum0[lc(o)];
rsum0[o] = color[rc(o)] == 0 ? rsum0[lc(o)] + rsum0[rc(o)] : rsum0[rc(o)];
sum0[o] = max(rsum0[lc(o)] + lsum0[rc(o)], max(sum0[lc(o)], sum0[rc(o)]));
if (sum1[o] == 0) color[o] = 0; else if (sum0[o] == 0) color[o] = 1; else color[o] = -1;
if (color[o] != -1) reversed[o] = false;
sum[o] = sum[lc(o)] + sum[rc(o)];
}
void set(int o, int l, int r, int L, int R, int value) {
if (l > R || r < L) return;
else if (L <= l && r <= R) creat(o, l, r, value);
else {
pushdown(o, l, r);
set(lc(o), l, mid, L, R, value);
set(rc(o), mid + 1, r, L, R, value);
pushup(o);
}
}
void reverse(int o, int l, int r, int L, int R) {
if (l > R || r < L) return;
else if (L <= l && r <= R) cover(o, l, r);
else {
pushdown(o, l, r);
reverse(lc(o), l, mid, L, R);
reverse(rc(o), mid + 1, r, L, R);
pushup(o);
}
}
int query_sum(int o, int l, int r, int L, int R) {
if (l > R || r < L) return 0;
else if (L <= l && r <= R) return sum[o];
else {
pushdown(o, l, r);
return query_sum(lc(o), l, mid, L, R) + query_sum(rc(o), mid + 1, r, L, R);
}
}
Ans query_len(int o, int l, int r, int L, int R) {
if (l > R || r < L) return Ans(0, 0, 0);
else if (L <= l && r <= R) return Ans(lsum1[o], rsum1[o], sum1[o]);
else {
pushdown(o, l, r);
if (R <= mid) return query_len(lc(o), l, mid, L, R);
if (L > mid) return query_len(rc(o), mid + 1, r, L, R);
Ans p = query_len(lc(o), l, mid, L, R);
Ans q = query_len(rc(o), mid + 1, r, L, R);
return Ans(p.ls == mid - l + 1 ? p.ls + q.ls : p.ls,
q.rs == r - mid ? p.rs + q.rs : q.rs,
max(max(p.s, q.s), p.rs + q.ls));
}
}
void build(int o, int l, int r) {
if (l > r) return;
else if (l == r) creat(o, l, r, a[l]);
else {
build(lc(o), l, mid);
build(rc(o), mid + 1, r);
pushup(o);
}
}
};
SegTree root;
int main() {
int T;
scanf("%d", &T);
while (T--) {
int n, m;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
root.clear();
root.build(1, 1, n);
for (int i = 1; i <= m; i++) {
int opt, x, y;
scanf("%d%d%d", &opt, &x, &y);
x++; y++;
if (opt == 0) root.set(1, 1, n, x, y, 0);
else if (opt == 1) root.set(1, 1, n, x, y, 1);
else if (opt == 2) root.reverse(1, 1, n, x, y);
else if (opt == 3) printf("%d\n", root.query_sum(1, 1, n, x, y));
else if (opt == 4) printf("%d\n", root.query_len(1, 1, n, x, y).s);
}
}
return 0;
}