问题描述
沙滩上有一些石头,石头的颜色是白色或者黑色。小羊会魔法,它能把连续一段的石头,黑色变成白色,白色变成黑色。小羊喜欢黑色,她想知道某些区间中最长的连续黑石头是多少个。
输入格式
第一行一个整数 n(1≤n≤100000)。
第二行 n 个整数,表示石头的颜色,0 是白色,1 是黑色。
第三行一个整数 m(1≤m≤100000)。
接下来 m 行,每行三个整数 x,i,j。
x=1 表示改变 [i,j] 石头的颜色。
x=0 表示询问 [i,j] 最长连续黑色石头的长度。
输出格式
当 x=0 时,输出答案。
样例输入
4
1 0 1 0
5
0 1 4
1 2 3
0 1 4
1 3 3
0 4 4
样例输出
1
2
0
AC代码
#include <cstdio>
#include <algorithm>
using namespace std;
/*务必分清l,r 和tree[p].l,tree[p].r。代码是大佬的。*/
const int kMax = 100000 + 10;
const int kInf = 1e9;
struct node {
int l, r;
int lw, rw;
int lb, rb;
int maxw, maxb;
bool change;
} tree[kMax << 2];
void pushup(int p) {//上压统计连续黑色石头的长度
//左孩子
tree[p].lw = tree[p << 1].lw;//左孩子里左边白色石头的最长长度
if(tree[p].lw == tree[p << 1].r - tree[p << 1].l + 1)//左孩子整段都是白色石头
tree[p].lw += tree[p << 1 | 1].lw;//加上右孩子左边的白色石头
tree[p].lb = tree[p << 1].lb;//左孩子左边黑色石头长度
if(tree[p].lb == tree[p << 1].r - tree[p << 1].l + 1)//左孩子全是黑的
tree[p].lb += tree[p << 1 | 1].lb;//加上右孩子左边里的黑色石头
//右孩子
tree[p].rw = tree[p << 1 | 1].rw;//右边白色长度
if(tree[p].rw == tree[p << 1 | 1].r - tree[p << 1 | 1].l + 1)//全是白色的
tree[p].rw += tree[p << 1].rw;//加上左孩子右边的白色孩子长度
tree[p].rb = tree[p << 1 | 1].rb;//右边黑色石头长度
if(tree[p].rb == tree[p << 1 | 1].r - tree[p << 1 | 1].l + 1)//全是黑的
tree[p].rb += tree[p << 1].rb;//加左孩子靠右边端的黑色
//要么左孩子,要么右孩子,要么连起来,取其中最长长度。
tree[p].maxw = max(max(tree[p << 1].maxw, tree[p << 1 | 1].maxw),
tree[p << 1].rw + tree[p << 1 | 1].lw);
tree[p].maxb = max(max(tree[p << 1].maxb, tree[p << 1 | 1].maxb),
tree[p << 1].rb + tree[p << 1 | 1].lb);
}
void pushdown(int p) {
if(tree[p].change) {
swap(tree[p << 1].maxw, tree[p << 1].maxb);//反正是最大的
swap(tree[p << 1].lw, tree[p << 1].lb);//
swap(tree[p << 1].rw, tree[p << 1].rb);//
swap(tree[p << 1 | 1].maxw, tree[p << 1 | 1].maxb);//一样
swap(tree[p << 1 | 1].lw, tree[p << 1 | 1].lb);//
swap(tree[p << 1 | 1].rw, tree[p << 1 | 1].rb);
tree[p << 1].change = !tree[p << 1].change;//延迟标记叠加,精髓所在
tree[p << 1 | 1].change = !tree[p << 1 | 1].change;
tree[p].change = false;
}
}
void build(int p, int l, int r) {
tree[p].l = l;
tree[p].r = r;
tree[p].change = false;
if(l == r) {
int t;
scanf("%d", &t);
tree[p].maxb = tree[p].lb = tree[p].rb = t == 1;//叶子节点是否是黑色
tree[p].maxw = tree[p].lw = tree[p].rw = t == 0;//叶子节点是否是白色
return;
}
int m = (l + r) >> 1;
build(p << 1, l, m);
build(p << 1 | 1, m + 1, r);
pushup(p);
}
void update(int p, int l, int r) {
if(l <= tree[p].l && r >= tree[p].r) {
swap(tree[p].maxw, tree[p].maxb);
swap(tree[p].lw, tree[p].lb);
swap(tree[p].rw, tree[p].rb);
tree[p].change = !tree[p].change;
return;
}
pushdown(p);
int m = (tree[p].l + tree[p].r) >> 1;
if(l <= m) update(p << 1, l, r);
if(r > m) update(p << 1 | 1, l, r);
pushup(p);
}
int query(int p, int l, int r) {
if(l <= tree[p].l && r >= tree[p].r) {
return tree[p].maxb;
}
pushdown(p);
int m = (tree[p].l + tree[p].r) >> 1;
int res = 0;
if(l <= m) res = max(res, query(p << 1, l, r));
if(r > m) res = max(res, query(p << 1 | 1, l, r));
if(l <= m && r > m) res = max(res,//这里是个坑,l,r可能更小。
min(m - l + 1, tree[p << 1].rb) +
min(r - m, tree[p << 1 | 1].lb));
pushup(p);
return res;
}
int main() {
int n, m, op, l, r;
scanf("%d", &n);
build(1, 1, n);
scanf("%d", &m);
while(m --) {
scanf("%d%d%d", &op, &l, &r);
if(op == 1) {
update(1, l, r);
} else {
printf("%d\n", query(1, l, r));
}
}
return 0;
}