思路如下:
1.len表示线段树当前区间内的满足要求的最长连续子串长度
2.因为需要不连续,所以记录下当前区间的左右端点head和tail,在pushUp时更新
详细在注释
代码:
#include<bits/stdc++.h>
#define N 500005
#define lc x<<1
#define rc x<<1|1
using namespace std;
struct Node{
int l,r,len;
bool head,tail;
}tr[N<<2];
int n,q,a;
inline void pushUp(int x){
tr[x].head=tr[lc].head; //当前区间的左就是左孩子的左
tr[x].tail=tr[rc].tail; //右同理
if((tr[lc].tail^tr[rc].head)==1) //当其结构(左孩子的右与右孩子的左)为"01"或"10"时,满足要求,整个区间也一定满足要求
tr[x].len=tr[lc].len+tr[rc].len;
else
tr[x].len=max(tr[lc].len,tr[rc].len); //未满足要求,就取两区间最大值
return ;
}
void build(int x,int l,int r){
tr[x].l=l;
tr[x].r=r;
if(l==r){
tr[x].len=1; //自己就是一个
tr[x].head=0; //单点头尾都一样
tr[x].tail=0;
return ;
}
int mid=(l+r)>>1;
build(lc,l,mid);
build(rc,mid+1,r);
pushUp(x);
return ;
}
void modify(int x,int l,int r){
if(tr[x].l==l&&tr[x].r==r){ //直到叶节点再修改
tr[x].head^=1; //取反
tr[x].tail^=1;
return ;
}
int mid=(tr[x].l+tr[x].r)>>1;
if(l<=mid)
modify(lc,l,r);
if(mid<r)
modify(rc,l,r);
pushUp(x);
return ;
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>q;
build(1,1,n);
while(q--){
cin>>a;
modify(1,a,a); //单点修改
cout<<tr[1].len<<"\n"; //答案是根的最长满足要求的序列长度
}
return 0;
}