P6492 COCI2010-2011 6 STEP

题目描述

给定一个长度为 \(n\) 的字符序列 \(a\),初始时序列中全部都是字符 L

\(q\) 次修改,每次给定一个 \(x\),若 \(a_x\)L,则将 \(a_x\) 修改成 R,否则将 \(a_x\) 修改成 L

对于一个只含字符 LR 的字符串 \(s\),若其中不存在连续的 LR,则称 \(s\) 满足要求。

每次修改后,请输出当前序列 \(a\) 中最长的满足要求的连续子串的长度。

输入格式

第一行有两个整数,分别表示序列的长度 \(n\) 和修改操作的次数 \(q\)

接下来 \(q\) 行,每行一个整数,表示本次修改的位置 \(x\)

输出格式

对于每次修改操作,输出一行一个整数表示修改 \(a\) 中最长的满足要求的子串的长度。

样例 #1

样例输入 #1

6 2
2
4

样例输出 #1

3
5

样例 #2

样例输入 #2

6 5
4
1
1
2
6

样例输出 #2

3
3
3
5
6

提示

数据规模与约定

对于全部的测试点,保证 \(1 \leq n, q \leq 2 \times 10^5\)\(1 \leq x \leq n\)

分析

假设 \(L=0,R=1\)

首先可以想到用线段树维护答案区间的左右端点,合并信息时(pushup)需要考虑到多种情况

\(lson[i],rson[i]\):线段树中 \(i\) 节点的左右儿子

\(ans[i]\):线段树中 \(i\) 节点所维护的区间的答案最大值

\(s[i],b[i]\):线段树中 \(i\) 节点所维护的区间的从左端点开始的答案的最大值(前缀);从右端点开始的答案的最大值(后缀)

那么这样子记录可以 \(O(1)\) 完成信息的维护

对于 pushup 操作,可以分成两种情况:

① 当前区间的左儿子的右端点与右儿子的左端点相同

那么大区间的答案为两个子区间答案的最大值

② 当前区间的左儿子的右端点与右儿子的左端点不同

除了考虑上述的情况外,我们还要考虑两个区间合并在一起时对答案产生的贡献

那么使用 \(s,h\) 数组可以轻松解决

接下来考虑怎样维护 \(s,h\) 数组

\(s,h\) 数组所维护的区间小于当前区间的长度

所以更新完信息后大区间的 \(s\) 就是左端点的 \(s\)\(h\) 同理

\(s,h\) 数组所维护的区间等于当前区间的长度

此时需要考虑整个左区间和右区间的 \(s\) 所产生的贡献,\(h\) 同理

#include<bits/stdc++.h>
using namespace std;
int n,q;
int s[200005<<2],b[200005<<2],lson[200005<<2],rson[200005<<2],ans[200005<<2];
void work(int x,int y){ans[x]=s[x]=b[x]=1,lson[x]=rson[x]=y;}
void pushup(int num,int l,int r){
	int mid=l+r>>1;
	if(lson[num<<1|1]^rson[num<<1])ans[num]=max(s[num<<1|1]+b[num<<1],max(ans[num<<1],ans[num<<1|1]));
	else ans[num]=max(ans[num<<1],ans[num<<1|1]);
	lson[num]=lson[num<<1],rson[num]=rson[num<<1|1];
	if(s[num<<1]==mid-l+1&&(lson[num<<1|1]^rson[num<<1]))s[num]=s[num<<1]+s[num<<1|1];
	else s[num]=s[num<<1];
	if(b[num<<1|1]==r-mid&&(lson[num<<1|1]^rson[num<<1]))b[num]=b[num<<1]+b[num<<1|1];
	else b[num]=b[num<<1|1];
}
void build(int l,int r,int num){
	if(l==r){
		work(num,0);
		return;
	}
	int mid=l+r>>1;
	build(l,mid,num<<1),build(mid+1,r,num<<1|1);
	pushup(num,l,r);
}
void change(int l,int r,int num,int k){
	if(l==r){
		work(num,!lson[num]);
		return;
	}
	int mid=l+r>>1;
	if(k<=mid)change(l,mid,num<<1,k);
	else change(mid+1,r,num<<1|1,k);
	pushup(num,l,r);
}
int main(){
	cin>>n>>q;
	build(1,n,1);
	for(int i=1,x;i<=q;i++){
		cin>>x;
		change(1,n,1,x);
		cout<<ans[1]<<endl;
	}
	return 0;
}
posted @ 2023-06-24 14:04  alex_liu09  阅读(147)  评论(0)    收藏  举报