令
ai
表示前
i
个数中
如果只考虑左端点的限制,那么对于区间内所有数,必须满足
枚举每个点作为左端点,在线段树上二分求出能达到的最远位置。右端点同理。
然后双指针扫一遍,再用一颗权值线段树维护答案就好了。
#include<bits/stdc++.h>
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline void Read(int& x){
char c=nc();
for(;c<'0'||c>'9';c=nc());
for(x=0;c>='0'&&c<='9';x=x*10+c-48,c=nc());
}
const int N=1000010;
const int INF=1e9;
#define x first
#define y second
int k,n,cnt1,cnt2,a[N];
bool b[N],p[N<<2];
bool f;
int mn[N<<2];
int Ans;
pair<int,int>c[N],d[N];
inline void Build(int x,int l,int r){
if(l==r){
mn[x]=a[l];
return;
}
int Mid=l+r>>1;
Build(x<<1,l,Mid);Build(x<<1|1,Mid+1,r);
mn[x]=min(mn[x<<1],mn[x<<1|1]);
}
inline void Query(int x,int l,int r,int L,int R,int y){
if(!f||mn[x]>=y||l>R||r<L)return;
int Mid=l+r>>1;
if(l==r){
if(mn[x]<y)f=0;k=l-1;
return;
}
Query(x<<1,l,Mid,L,R,y);Query(x<<1|1,Mid+1,r,L,R,y);
}
void Update(int x,int l,int r,int y){
p[x]=1;
if(l==r)return;
int Mid=l+r>>1;
if(y<=Mid)Update(x<<1,l,Mid,y);
else Update(x<<1|1,Mid+1,r,y);
}
void Find(int x,int l,int r,int L,int R){
if(!f||!p[x]||l>R||r<L)return;
int Mid=l+r>>1;
if(l==r){
f=0;k=l;
return;
}
Find(x<<1|1,Mid+1,r,L,R);Find(x<<1,l,Mid,L,R);
}
int main(){
Read(n);
char C=nc();
for(;C!='j'&&C!='p';C=nc());
for(int i=1;i<=n;i++)b[i]=(C=='p'),a[i]=a[i-1]+(b[i]?1:-1),C=nc();
Build(1,1,n);
for(int i=1;i<=n;i++)
if(b[i])f=1,k=n,Query(1,1,n,i,n,a[i-1]),c[++cnt1].x=n-k+1,c[cnt1].y=n-i+1;
for(int i=1;i<=(n>>1);i++)swap(b[i],b[n-i+1]);
for(int i=1;i<=n;i++)a[i]=a[i-1]+(b[i]?1:-1);
Build(1,1,n);
for(int i=1;i<=n;i++)
if(b[i])f=1,k=n,Query(1,1,n,i,n,a[i-1]),d[++cnt2].x=i,d[cnt2].y=k;
sort(c+1,c+cnt1+1);sort(d+1,d+cnt2+1);
int j=0;
for(int i=1;i<=cnt2;i++){
for(;j<cnt1&&c[j+1].x<=d[i].x;)Update(1,1,n,c[++j].y);
f=1;k=0;
Find(1,1,n,d[i].x,d[i].y);
Ans=max(Ans,k-d[i].x+1);
}
cout<<Ans<<endl;
return 0;
}