0 a b将区间[a,b]所有数全部变成0
1 a b将区间[a,b]所有数全部变成1
2 a b将区间[a,b]中所有数0 1互换,0变1,1变0
3 a b输出区间[a,b]中1的个数
4 a b输出区间[a,b]中最长连续1的个数
涉及到线段树的多种操作。
mxL[0]表示左边最长连续0的个数
mxR[0]表示右边最长连续0的个数
mx[0]表示当前区间最长连续0的个数
mxL[1],mxR[1],mx[1]同上
为什么要定义mx[0],和mx[1]这些标记,是为了在区间翻转的时候得到互相的值。查询区间最长连续1个数的过程中;
maxl=[l,m]上最长连续1个数
maxl=[m+1,r]上最长连续1的个数
maxm=min(m−l+1,左孩子的rs)+min(r−m,右孩子的ls)
结果应该是这三个中的最大值,即 max(maxl,maxr,maxm)
有个地方需要注意下,就是懒惰传递的先后问题。
我一直WA在这里,后看别人解释,如果覆盖的话,那么异或已经没有用了,把异或标记为0即可。还有一个问题,怎么确定是先覆盖再异或,还是先异或再覆盖。
这两个的结果可能是不同的,所以必须确定,是怎么的一种传递方法?传递的时候,如果是覆盖传递,那么子节点的异或失效。如果是异或传递,无影响。(因为存在异或,说明之前不会有覆盖经过这里)
my code
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ls (o<<1)
#define rs (o<<1|1)
#define lson ls, L, M
#define rson rs, M+1, R
using namespace std;
const int N = 1e5 + 10;
int n, m;
int mxL[N<<2][2], mxR[N<<2][2], mx[N<<2][2];
int sum[N<<2];
int XOR[N<<2], cov[N<<2];
inline int max(int a, int b, int c) { return max(a, max(b, c)); }
void setXOR(int o, int L, int R) {
XOR[o] ^= 1;
swap(mxL[o][0], mxL[o][1]);
swap(mxR[o][0], mxR[o][1]);
swap(mx[o][0], mx[o][1]);
sum[o] = (R - L + 1) - sum[o];
}
void setCov(int o, int L, int R) {
int cur = cov[o], tmp = cov[o]^1;
int len = R - L + 1;
mxL[o][cur] = mxR[o][cur] = mx[o][cur] = len;
mxL[o][tmp] = mxR[o][tmp] = mx[o][tmp] = 0;
sum[o] = cur * len;
}
void pushDown(int o, int L, int R) {
int M = (L + R)/2;
if(cov[o] != -1) {
cov[ls] = cov[rs] = cov[o];
XOR[ls] = XOR[rs] = false;
setCov(lson);
setCov(rson);
cov[o] = -1;
}
if(XOR[o]) {
setXOR(lson);
setXOR(rson);
XOR[o] = false;
}
}
void merge(int o, int L, int R, int x) {
int M = (L + R)/2;
mxL[o][x] = mxL[ls][x]; mxR[o][x] = mxR[rs][x];
int len1 = M - L + 1, len2 = R - M;
if(mxL[ls][x] == len1) mxL[o][x] += mxL[rs][x];
if(mxR[rs][x] == len2) mxR[o][x] += mxR[ls][x];
int midlen = mxR[ls][x] + mxL[rs][x];
mx[o][x] = max(mx[ls][x], mx[rs][x], midlen);
}
void pushUp(int o, int L, int R) {
merge(o, L, R, 1);
merge(o, L, R, 0);
sum[o] = sum[ls] + sum[rs];
}
void modify(int o, int L, int R, int ql, int qr, int op) {
if(ql <= L && R <= qr) {
if(op < 2) {
cov[o] = op;
XOR[o] = false;
setCov(o, L, R);
}else {
setXOR(o, L, R);
}
return ;
}
pushDown(o, L, R);
int M = (L + R)/2;
if(ql <= M) modify(lson, ql, qr, op);
if(qr > M) modify(rson, ql, qr, op);
pushUp(o, L, R);
}
int queryMax(int o, int L, int R, int ql, int qr) {
if(ql <= L && R <= qr) return mx[o][1];
int M = (L + R)/2, ret = 0;
pushDown(o, L, R);
if(qr <= M) ret = queryMax(lson, ql, qr);
else if(ql > M) ret = queryMax(rson, ql, qr);
else {
int len1 = queryMax(lson, ql, M), len2 = queryMax(rson, M+1, qr);
int len0 = min(mxR[ls][1], (M - ql + 1)) + min(mxL[rs][1], (qr - M));
ret = max(len0, len1, len2);
}
pushUp(o, L, R);
return ret;
}
int querySum(int o, int L, int R, int ql, int qr) {
if(ql <= L && R <= qr) return sum[o];
int M = (L + R)/2, ret = 0;
pushDown(o, L, R);
if(ql <= M) ret += querySum(lson, ql, qr);
if(qr > M) ret += querySum(rson, ql, qr);
pushUp(o, L, R);
return ret;
}
void build(int o, int L, int R) {
cov[o] = -1, XOR[o] = false;
if(L == R) {
int val;
scanf("%d", &val);
cov[o] = val;
setCov(o, L, R);
return ;
}
int M = (L + R)/2;
build(lson);
build(rson);
pushUp(o, L, R);
}
int main() {
int op, a, b;
int T;
scanf("%d", &T);
while(T--) {
scanf("%d%d", &n, &m);
build(1, 0, n-1);
while(m--) {
scanf("%d%d%d", &op, &a, &b);
if(op <= 2) {
modify(1, 0, n-1, a, b, op);
}else if(op == 3) {
printf("%d\n", querySum(1, 0, n-1, a, b));
}else {
printf("%d\n", queryMax(1, 0, n-1, a, b));
}
}
}
return 0;
}