洛谷P6492 COCI 2010 2011 6 STEP
#算法/线段树
题目
这题代码总体写出来不是很难,我们只需要围绕以下思路即可
ans代表区间满足要求的连续子串的长度。
lans代表以左端为首满足要求的连续子串的长度。
rans代表以右端为尾满足要求的连续子串的长度。
lch代表左端的字符,我们将初始字符都定义为0
rch代表右端的字符
len代表区间长度
1.拆分
与平常的线段树一样,一个区间拆分成左右区间考虑
2.长度更新
先将大区间的最长长度定义成左右区间的最长长度,其次,判断中间两个的值是否相同,如果不同,我们将左半部分最右侧的值加上右半部分左侧的最大长度,将相加的值再与最长长度进行比较
ans[p]=max(ans[lc],ans[rc]);int lrc=rch[lc];int rlc=Lch[rc];if(lrc!=rlc){ans[p]=max(ans[p],rans[lc]+lans[rc]);}
3.更新区间两端长度
更新左侧:先将区间最左侧的长度更新为左半部分最左侧值,然后,判断左侧值长度是否与左区间相同,如果相同,我们再判断中间两个的值是否相同,如果不同,我们再将左侧的值加上右半部分左侧的值
更新右侧同理
lans[p]=lans[lc];rans[p]=rans[rc];if(lans[lc]==len[lc]&&rch[lc]!=Lch[rc]){lans[p]+=lans[rc];}if(rans[rc]==len[rc]&&rch[lc]!=Lch[rc]){rans[p]+=rans[lc];}
完整代码
#include<iostream>#include<string>using namespace std;#define lc p<<1#define rc p<<1|1const int N=2e6;int Lch[N];int rch[N];int ans[N];int lans[N];int rans[N];int len[N];void build(int p,int l,int r){if(l>=r){ ans[p]=lans[p]=rans[p]=1;Lch[p]=rch[p]=0;len[p]=1;return;}int mid=l+r>>1;build(lc,l,mid);build(rc,mid+1,r); ans[p]=lans[p]=rans[p]=1;Lch[p]=rch[p]=0;len[p]=r-l+1;}bool outRange(int pos,int L,int R){if(pos<L||pos>R)return true;return false;}void change(int p,int l,int r,int pos){if(outRange(pos,l,r))return;if(l==r){Lch[p]=rch[p]=Lch[p]^1;return;}int mid=l+r>>1;change(lc,l,mid,pos);change(rc,mid+1,r,pos);ans[p]=max(ans[lc],ans[rc]);int lrc=rch[lc];int rlc=Lch[rc];if(lrc!=rlc){ans[p]=max(ans[p],rans[lc]+lans[rc]);}rch[p]=rch[rc];Lch[p]=Lch[lc];lans[p]=lans[lc];rans[p]=rans[rc];if(lans[lc]==len[lc]&&rch[lc]!=Lch[rc]){lans[p]+=lans[rc];}if(rans[rc]==len[rc]&&rch[lc]!=Lch[rc]){rans[p]+=rans[lc];}}void query(int p,int l,int r,int pos){if(outRange(pos,l,r))return;if(l==r){cout<<Lch[p];return;}int mid=l+r>>1;query(lc,l,mid,pos);query(rc,mid+1,r,pos);}int main(void){int n,q;cin>>n>>q;build(1,1,n);for(int i=1;i<=q;i++){int pos;cin>>pos;change(1,1,n,pos);cout<<ans[1]<<endl;}}