个人感觉思路挺正确,但只拿了8pts
查看原帖
个人感觉思路挺正确,但只拿了8pts
823949
Hhy882577楼主2024/8/7 10:33

思路如下:

  • 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;
}
2024/8/7 10:33
加载中...