[SCOI2010]序列操作
我可以铭记一生的蛇皮线段树
左左右右上上下下中间两头
咳咳,没什么好说的了,开始写吧。
我,可真是,写了zz三天。
#include <cstdio>
#include <iostream>
#include<algorithm>
using namespace std;
struct ANS {
int l, r, ans, len;
ANS(int a=0, int b = 0, int c = 0, int d = 0) : l(a), r(b), ans(c), len(d) {}
};
int n, q,a[4000101];
int sum[4000101], l1[4000101], r1[4000101], l0[4000101], r0[4000101];
int lg1[4000101], lg0[4000101],add1[4000101], add2[4000101];
void pushup(int rt, int l, int r){
int mid = l + r>>1;
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
l1[rt] = l1[rt<<1], r1[rt] = r1[rt<<1|1];
if(l1[rt]==mid-l + 1) l1[rt] += l1[rt<<1|1];
if(r1[rt]==r-mid) r1[rt] += r1[rt<<1];
l0[rt]=l0[rt<<1], r0[rt] = r0[rt<<1|1];
if(l0[rt]==mid-l + 1) l0[rt] += l0[rt<<1|1];
if(r0[rt] == r - mid) r0[rt] += r0[rt<<1];
lg1[rt]=max(max(lg1[rt<<1],lg1[rt<<1|1]),r1[rt<<1]+l1[rt<<1|1]);
lg0[rt]=max(max(lg0[rt<<1], lg0[rt<<1|1]),r0[rt<<1]+l0[rt<<1|1]);
}
void pushdown(int rt, int ln, int rn){
if(add1[rt]!=-1){
int c=add1[rt];
add2[rt<<1]=0;add1[rt<<1]=c;
sum[rt<<1]=ln*c;
l1[rt<<1]=r1[rt<<1]=lg1[rt<<1]=c?ln:0;
l0[rt<<1]=r0[rt<<1]=lg0[rt<<1]=c?0:ln;
c=add1[rt];
add2[rt<<1|1]=0;add1[rt<<1|1]=c;
sum[rt<<1|1]=rn*c;
l1[rt<<1|1]=r1[rt<<1|1]=lg1[rt<<1|1]=c?rn:0;
l0[rt<<1|1]=r0[rt<<1|1]=lg0[rt<<1|1]=c?0:rn;
add1[rt] = -1;
}
if(add2[rt]){
add2[rt<<1]^=1;
sum[rt<<1]=ln-sum[rt<<1];
swap(lg1[rt<<1],lg0[rt<<1]);
swap(l1[rt<<1],l0[rt<<1]);
swap(r1[rt<<1],r0[rt<<1]);
add2[rt<<1|1]^=1;
sum[rt<<1|1]=rn-sum[rt<<1|1];
swap(lg1[rt<<1|1],lg0[rt<<1|1]);
swap(l1[rt<<1|1],l0[rt<<1|1]);
swap(r1[rt<<1|1],r0[rt<<1|1]);
add2[rt] = 0;
}
}
void build(int rt, int l, int r) {
add1[rt] = -1, add2[rt] = 0;
if(l==r){
sum[rt]=a[l];
l1[rt]=r1[rt]=lg1[rt]=a[l];
l0[rt]=r0[rt]=lg0[rt]=!a[l];
return ;
}
int mid =l + r >> 1;
build(rt<<1,l,mid);
build(rt<<1|1,mid+1,r);
pushup(rt,l,r);
}
void modify(int rt, int l, int r, int L, int R, int c) {
if(L <= l && r <= R) {
add1[rt] = c;
add2[rt]=0;
sum[rt]=(r-l+1)*c;
l1[rt]=r1[rt]=lg1[rt]=c?(r-l+1):0;
l0[rt]=r0[rt]=lg0[rt]=c?0:(r - l +1);
return ;
}
int mid=l+r>>1;
pushdown(rt,mid-l+1,r-mid);
if(mid>=L)modify(rt<<1,l,mid,L,R,c);
if(mid<R)modify(rt<<1|1,mid+1,r,L,R,c);
pushup(rt,l,r);
}
void reverse_(int rt, int l, int r, int L, int R) {
if(L<=l&&r<=R){
add2[rt]^=1;
sum[rt]=(r-l+1)-sum[rt];
swap(lg1[rt],lg0[rt]);
swap(l1[rt],l0[rt]);
swap(r1[rt],r0[rt]);
return;
}
int mid=l+r>>1;
pushdown(rt,mid-l+1,r-mid);
if(mid>=L)reverse_(rt << 1,l,mid, L, R);
if(mid<R)reverse_(rt << 1 | 1, mid + 1, r, L, R);
pushup(rt, l, r);
}
int query1(int rt, int l, int r,int L, int R){
if(L<=l&& r<=R)return sum[rt];
int mid =l+r>>1;
pushdown(rt,mid-l+1,r-mid);
int ans=0;
if(mid>=L)ans+=query1(rt << 1, l, mid, L, R);
if(mid<R)ans+=query1(rt << 1 | 1, mid + 1, r, L, R);
return ans;
}
ANS query2(int rt, int l, int r, int L, int R) {
if(L == l && r == R) return ANS(l1[rt], r1[rt], lg1[rt], r - l + 1);
int mid = l + r >> 1;
pushdown(rt,mid-l+1,r-mid);
if(R <= mid)return query2(rt << 1, l, mid, L, R);
if(L > mid)return query2(rt << 1 | 1, mid + 1, r, L, R);
ANS al=query2(rt << 1,l,mid,L,mid);
ANS ar=query2(rt<<1 | 1, mid+1,r,mid+1, R);
return ANS((al.l==al.len?al.l+ar.l:al.l),(ar.r == ar.len?ar.r+al.r:ar.r),max(max(al.ans,ar.ans),al.r+ar.l),al.len+ar.len);//全场最坑
}
int main() {
scanf("%d%d", &n, &q);
for(int i = 1; i <= n;i++)
scanf("%d", &a[i]);
build(1, 1, n);
while(q--){
int opt,x,y;
scanf("%d%d%d",&opt,&x,&y);
++x,++y;
if(opt==0)modify(1, 1, n, x, y, 0);
if(opt==1)modify(1,1,n,x,y,1);
if(opt==2)reverse_(1, 1, n, x, y);
if(opt ==3)printf("%d\n", query1(1, 1, n, x, y));
if(opt == 4)printf("%d\n", query2(1, 1, n, x, y).ans);
}
return 0;
}