bzoj1858: [Scoi2010]序列操作(線段樹)

Hanks_o發表於2018-04-16

題目傳送門

解法:
線段樹。
因為01要交換。
所以0和1的資訊都要維護。
維護最長連續一段,總數,從左端點連續,從右端點連續。
然後打上覆蓋和翻轉標記。
不允許兩種標記同時存在。

如果要打覆蓋標記,那麼翻轉標記就沒用了。
如果打翻轉標記,那麼覆蓋標記取反就行。

程式碼實現:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
struct node {int l,r,lc,rc,c[2],s[2],Lc[2],Rc[2],size,lazy,fz;}tr[210000];int trlen;
void bt(int l,int r) {
    int now=++trlen;tr[now].l=l;tr[now].r=r;tr[now].lc=tr[now].rc=-1;
    tr[now].c[1]=tr[now].c[0]=0;tr[now].s[1]=tr[now].s[0]=0;
    tr[now].Lc[0]=tr[now].Lc[1]=0;tr[now].Rc[0]=tr[now].Rc[1]=0;
    tr[now].size=r-l+1;tr[now].lazy=-1;tr[now].fz=0;
    if(l<r) {int mid=(l+r)/2;tr[now].lc=trlen+1;bt(l,mid);tr[now].rc=trlen+1;bt(mid+1,r);}
}
void update(int now) {
    int lc=tr[now].lc,rc=tr[now].rc;if(lc==-1)return ;
    if(tr[now].lazy!=-1) {
        int t=tr[now].lazy;
        tr[lc].c[t]=tr[lc].size;tr[rc].c[t]=tr[rc].size;
        tr[lc].c[1-t]=tr[rc].c[1-t]=0;
        tr[lc].Lc[t]=tr[lc].Rc[t]=tr[lc].size;
        tr[rc].Lc[t]=tr[rc].Rc[t]=tr[rc].size;
        tr[lc].Lc[1-t]=tr[lc].Rc[1-t]=0;
        tr[rc].Lc[1-t]=tr[rc].Rc[1-t]=0;
        tr[lc].s[t]=tr[lc].size;tr[lc].s[1-t]=0;
        tr[rc].s[t]=tr[rc].size;tr[rc].s[1-t]=0;
        tr[lc].fz=tr[rc].fz=0;tr[lc].lazy=tr[rc].lazy=tr[now].lazy;tr[now].lazy=-1;
    }if(tr[now].fz!=0) {
        swap(tr[lc].c[0],tr[lc].c[1]);swap(tr[rc].c[0],tr[rc].c[1]);
        swap(tr[lc].s[0],tr[lc].s[1]);swap(tr[rc].s[0],tr[rc].s[1]);
        swap(tr[lc].Lc[0],tr[lc].Lc[1]);swap(tr[rc].Lc[0],tr[rc].Lc[1]);
        swap(tr[lc].Rc[0],tr[lc].Rc[1]);swap(tr[rc].Rc[0],tr[rc].Rc[1]);
        tr[lc].fz^=1;tr[rc].fz^=1;tr[now].fz=0;
        if(tr[lc].fz==1&&tr[lc].lazy!=-1){tr[lc].lazy^=1;tr[lc].fz=0;}
        if(tr[rc].fz==1&&tr[rc].lazy!=-1){tr[rc].lazy^=1;tr[rc].fz=0;}
    }
}
void change(int now,int l,int r,int k) {
    update(now);
    if(tr[now].l==l&&tr[now].r==r) {
        tr[now].c[k]=tr[now].size;tr[now].c[1-k]=0;
        tr[now].s[k]=tr[now].size;tr[now].s[1-k]=0;
        tr[now].Lc[k]=tr[now].Rc[k]=tr[now].size;
        tr[now].Lc[1-k]=tr[now].Rc[1-k]=0;
        tr[now].lazy=k;tr[now].fz=0;return ;
    }
    int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
    if(r<=mid)change(lc,l,r,k);else if(l>mid)change(rc,l,r,k);
    else {change(lc,l,mid,k);change(rc,mid+1,r,k);}
    for(int i=0;i<=1;i++) {
        tr[now].s[i]=tr[lc].s[i]+tr[rc].s[i];
        if(tr[lc].Lc[i]==tr[lc].size)tr[now].Lc[i]=tr[lc].size+tr[rc].Lc[i];
        else tr[now].Lc[i]=tr[lc].Lc[i];
        if(tr[rc].Rc[i]==tr[rc].size)tr[now]. Rc[i]=tr[rc].size+tr[lc].Rc[i];
        else tr[now].Rc[i]=tr[rc].Rc[i];
        tr[now].c[i]=max(max(tr[lc].c[i],tr[rc].c[i]),tr[lc].Rc[i]+tr[rc].Lc[i]);
    }
}
void fz(int now,int l,int r) {
    update(now);
    if(tr[now].l==l&&tr[now].r==r) {
        swap(tr[now].c[0],tr[now].c[1]);swap(tr[now].s[0],tr[now].s[1]);
        swap(tr[now].Lc[0],tr[now].Lc[1]);swap(tr[now].Rc[0],tr[now].Rc[1]);
        tr[now].fz^=1;if(tr[now].lazy!=-1&&tr[now].fz==1)tr[now].lazy^=1,tr[now].fz=0;
        return ;
    }
    int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
    if(r<=mid)fz(lc,l,r);else if(l>mid)fz(rc,l,r);
    else {fz(lc,l,mid);fz(rc,mid+1,r);}
    for(int i=0;i<=1;i++) {
        tr[now].s[i]=tr[lc].s[i]+tr[rc].s[i];
        if(tr[lc].Lc[i]==tr[lc].size)tr[now].Lc[i]=tr[lc].size+tr[rc].Lc[i];
        else tr[now].Lc[i]=tr[lc].Lc[i];
        if(tr[rc].Rc[i]==tr[rc].size)tr[now].Rc[i]=tr[rc].size+tr[lc].Rc[i];
        else tr[now].Rc[i]=tr[rc].Rc[i];
        tr[now].c[i]=max(max(tr[lc].c[i],tr[rc].c[i]),tr[lc].Rc[i]+tr[rc].Lc[i]);
    }
}
int find_sum(int now,int l,int r,int k) {
    update(now);
    if(tr[now].l==l&&tr[now].r==r)return tr[now].s[k];
    int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
    if(r<=mid)return find_sum(lc,l,r,k);else if(l>mid)return find_sum(rc,l,r,k);
    else return find_sum(lc,l,mid,k)+find_sum(rc,mid+1,r,k);
}
int find_max(int now,int l,int r,int k) {
    update(now);
    if(tr[now].l==l&&tr[now].r==r)return tr[now].c[k];
    int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)/2;
    if(r<=mid)return find_max(lc,l,r,k);else if(l>mid)return find_max(rc,l,r,k);
    else {
        int t=max(find_max(lc,l,mid,k),find_max(rc,mid+1,r,k));
        int tt=min(tr[lc].Rc[k],mid-l+1)+min(tr[rc].Lc[k],r-mid);
        return max(tt,t);
    }
}
int main() {
    //freopen("1858.in","r",stdin);freopen("1858.out","w",stdout); 
    int n,m;scanf("%d%d",&n,&m);trlen=0;bt(1,n);
    for(int i=1;i<=n;i++) {int k;scanf("%d",&k);change(1,i,i,k);}
    while(m--) {
        int t,x,y;scanf("%d%d%d",&t,&x,&y);x++;y++;
        if(t<=1)change(1,x,y,t);
        else if(t==2)fz(1,x,y);
        else if(t==3)printf("%d\n",find_sum(1,x,y,1));
        else printf("%d\n",find_max(1,x,y,1));
    }
    return 0;
}