线段树维护最长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;
}
}

浙公网安备 33010602011771号