原题
这题的一开始的思路就是将左右括号给化成-1与1的形式,因为它只支持这样的合法括号:
1.()是合法括号序列;
2.如果A是合法的,那么(A)也是合法的;
3.如果A和B都合法,那么AB合法。
所以便可以想出将‘(’为1,’)'为-1,那么就相当于是在求前缀合之间的关系(这个关系并不复杂,就是以pos为左端点,到最远的右端点,使前缀和为0,且,这个区间的前缀和中不可以包含-1),我们可以用线段树维护前缀和。
楼主一开始使用了二分,但是超时了。后来换了一种新思路。
旧思路(二分超时):
比如询问的是pos到n。我们首先可以求出pos-1的前缀合为las。然后再从pos到n的前缀和中求最小值fut。(如果s[pos]=’)’,直接输出0即可)
1:如果fut>las,不存在,输出0
2:如果fut=las,存在0,求出最靠右边的,前缀和为0的位置。它就是答案。
3:如果fut<las,存在-1,求从左向右数第一个-1的位置,它的左边的位置就是答案。
新思路:
一开始的超时代码:
#include<bits/stdc++.h>
#define lson k<<1,l,mid
#define rson k<<1|1,mid+1,r
using namespace std;
const int MX=5e5+9;
int T,n,m,pos,order,t[MX<<2],laze[MX<<2],a[MX],sum[MX];
char s[MX];
void build(int k,int l,int r){
laze[k]=0;
if( l==r ){
t[k]=sum[l];
return ;
}
int mid=(l+r)>>1;
build(lson);
build(rson);
t[k]=min(t[k<<1],t[k<<1|1]);
}
void pushdown(int k){
if( laze[k] ){
laze[k<<1]+=laze[k];
laze[k<<1|1]+=laze[k];
t[k<<1]+=laze[k];
t[k<<1|1]+=laze[k];
laze[k]=0;
}
}
void update(int k,int l,int r,int L,int val){
if( L<=l ){
t[k]+=val;
laze[k]+=val;
return ;
}
pushdown(k);
int mid=(l+r)>>1;
if( L<=mid )
update(lson,L,val);
update(rson,L,val);
t[k]=min(t[k<<1],t[k<<1|1]);
}
int que(int k,int l,int r,int L,int R){
if( !L )
return 0;
if( L<=l && r<=R )
return t[k];
pushdown(k);
int mid=(l+r)>>1,ans=MX;
if( L<=mid )
ans=min(ans,que(lson,L,R));
if( mid<R )
ans=min(ans,que(rson,L,R));
return ans;
}
int main()
{
// freopen("input.txt","r",stdin);
scanf("%d",&T);
while( T-- ){
scanf("%d %d",&n,&m);
scanf("%s",s+1);
for( int i=1 ; i<=n ; i++ )
a[i]=s[i]=='('?1:-1;
for( int i=1 ; i<=n ; i++ )
sum[i]=sum[i-1]+a[i];
build(1,1,n);
while( m-- ){
scanf("%d %d",&order,&pos);
if( order==1 ){
s[pos]=s[pos]==')'?'(':')';
update(1,1,n,pos,s[pos]=='('?2:-2);
}
else{
if( s[pos]==')' )
printf("0\n");
else{
int las=que(1,1,n,pos-1,pos-1);
int ans,fut=que(1,1,n,pos,n);
if( las==fut ){
int l=pos,r=n;
while( l<=r ){
int mid=(l+r)>>1;
if( las==que(1,1,n,mid,r) ){
l=mid+1;
ans=mid-pos;
}
else
r=mid-1;
}
printf("%d\n",ans);
}
else if( las>fut ){
int l=pos,r=n;
while( l<=r ){
int mid=(l+r)>>1;
if( las>que(1,1,n,l,mid) ){
r=mid-1;
ans=mid-pos;
}
else
l=mid+1;
}
printf("%d\n",ans);
}
else
printf("0\n");
}
}
}
}
return 0;
}
新思路:
#include<bits/stdc++.h>
#define lson k<<1,l,mid
#define rson k<<1|1,mid+1,r
using namespace std;
const int MX=5e5+9;
int T,n,m,order,x,t[MX<<2],laze[MX<<2],a[MX];
char s[MX];
void pushdown(int k){
if( laze[k] ){
laze[k<<1]+=laze[k];
laze[k<<1|1]+=laze[k];
t[k<<1]+=laze[k];
t[k<<1|1]+=laze[k];
laze[k]=0;
}
}
void build(int k,int l,int r){
laze[k]=0;
if( l==r ){
t[k]=a[l];
return ;
}
int mid=(l+r)>>1;
build(lson);
build(rson);
t[k]=min(t[k<<1],t[k<<1|1]);
}
void update(int k,int l,int r,int L,int val){
if( L<=l ){
t[k]+=val;
laze[k]+=val;
return ;
}
pushdown(k);
int mid=(l+r)>>1;
if( L<=mid )
update(lson,L,val);
update(rson,L,val);
t[k]=min(t[k<<1],t[k<<1|1]);
}
int que(int k,int l,int r,int L,int R){
if( L<=l && r<=R )
return t[k];
pushdown(k);
int mid=(l+r)>>1,ans=MX;
if( L<=mid )
ans=min(ans,que(lson,L,R));
if( mid<R )
ans=min(ans,que(rson,L,R));
return ans;
}
int que1(int k,int l,int r,int L,int R,int val){
if( l==r && t[k]==val )
return l;
pushdown(k);
int mid=(l+r)>>1;
if( L<=mid && t[k<<1]<=val ){
int ans=que1(lson,L,R,val);
if( ans>0 )
return ans;
}
if( mid<R && t[k<<1|1]<=val ){
int ans=que1(rson,L,R,val);
if( ans>0 )
return ans;
}
return -1;
}
int que2(int k,int l,int r,int L,int R,int val){
if( l==r && t[k]==val )
return l;
pushdown(k);
int mid=(l+r)>>1;
if( mid<R && t[k<<1|1]<=val ){
int ans=que2(rson,L,R,val);
if( ans>0 )
return ans;
}
if( L<=mid && t[k<<1]<=val ){
int ans=que2(lson,L,R,val);
if( ans>0 )
return ans;
}
return -1;
}
int main()
{
// freopen("input.txt","r",stdin);
scanf("%d",&T);
while( T-- ){
scanf("%d %d",&n,&m);
scanf("%s",s+1);
for( int i=1 ; i<=n ; i++ )
a[i]=a[i-1]+(s[i]=='('?1:-1);
build(1,1,n);
while( m-- ){
scanf("%d %d",&order,&x);
if( order==1 ){
s[x]=s[x]=='('?')':'(';
update(1,1,n,x,s[x]=='('?2:-2);
}
else{
if( s[x]==')' )
printf("0\n");
else{
int zuo=(x==1?0:que(1,1,n,x-1,x-1)); // 要小心x=0的时候,
int you=que(1,1,n,x,n);
if( zuo<you )
printf("0\n"); //当右边全部都是(时
else{
int pos=que1(1,1,n,x,n,zuo-1); // 求出第一个‘-1’(此-1非彼-1)的位置
if( pos==-1 )
pos=n+1;
int ans=que2(1,1,n,x,pos-1,zuo); // 在这个范围内求出最靠右的‘0’的位置
printf("%d\n",ans-x+1);
}
}
}
}
}
return 0;
}