P6492 COCI2010-2011 6 STEP
题目描述
给定一个长度为 \(n\) 的字符序列 \(a\),初始时序列中全部都是字符 L。
有 \(q\) 次修改,每次给定一个 \(x\),若 \(a_x\) 为 L,则将 \(a_x\) 修改成 R,否则将 \(a_x\) 修改成 L。
对于一个只含字符 L,R 的字符串 \(s\),若其中不存在连续的 L 和 R,则称 \(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;
}

浙公网安备 33010602011771号