线段树维护最长01交替区间

题目链接

思路:

每个节点额外维护的信息为,区间前缀最长01交替区间,区间后缀最长01交替区间,区间的最长01交替区间
由于单点修改,不需要维护懒标记
也就不需要pushdown操作
考虑pushup
当左儿子右端点的值和右儿子左端点的值不同时,显然可以连接起来
某个节点的最长前缀01区间:可以由左儿子的最长前缀01区间得到,当左儿子最长前缀01区间为整个区间时,可以由左儿子整个区间+右儿子最长前缀01区间构成
最长后缀区间同理
最长01区间可以由:左儿子的最长01区间或右儿子的最长01区间得到,或者 左儿子最长后缀+右儿子最长前缀 获得(满足条件时)

struct node{
    int l,r;
    int lv,mv,rv;
}tr[4*maxn];
int a[maxn];
void pushup(int p){
    tr[p].lv=tr[ls].lv;
    tr[p].rv=tr[rs].rv;
    if(a[tr[ls].r]!=a[tr[rs].l]){
        if(tr[ls].lv==tr[ls].r-tr[ls].l+1){
            tr[p].lv+=tr[rs].lv;
        }
        if(tr[rs].rv==tr[rs].r-tr[rs].l+1){
            tr[p].rv+=tr[ls].rv;
        }
    }
    tr[p].mv=max({a[tr[ls].r]!=a[tr[rs].l]?tr[ls].rv+tr[rs].lv:0,tr[ls].mv,tr[rs].mv});
}
void build(int p,int l,int r){
    tr[p].l=l;tr[p].r=r;
    if(l==r){
        tr[p].lv=tr[p].rv=tr[p].mv=1;
        return ;
    }
    int mid=l+r>>1;
    build(ls,l,mid);
    build(rs,mid+1,r);
    pushup(p);
}
void change(int p,int x){
    if(tr[p].l==tr[p].r&&tr[p].l==x){
        return;
    }   
    int mid=tr[p].l+tr[p].r>>1;
    if(x<=mid)change(ls,x);
    else change(rs,x);
    pushup(p);
}
void solve(){
    int n,q;cin>>n>>q;
    build(1,1,n);
    while(q--){
        int x;cin>>x;
        a[x]^=1;
        change(1,x);
        cout<<tr[1].mv<<endl;
    }
}

posted @ 2025-06-10 19:44  Marinaco  阅读(16)  评论(0)    收藏  举报
//雪花飘落效果