题目链接:http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1542
题意:给出一串匹配的括号,改变其中一个括号的方向,要求改变最左边的一个括号方向使得该串括号重新匹配
思路:((()))这样一个串括号,我们每遇到‘(’便加1,遇到’)‘便建1这样可以得到序列:1 2 3 2 1 0,可以发现如果一串括号是匹配的,那么该序列的末尾必定是0且序列的每一位都大于0
如果我们将某个'('变为‘)’的话,序列中该位置和其后面的数全都-2,要使序列满足末尾是0且序列的每一位都大于0的条件,我们只需要找到最左边的一个‘)’括号将其变为’(‘就可以了
如果我们将某个‘)’变成‘(’的话,序列中该位置和其后面的数全都-2,要使序列满足末尾是0便可以使括号重新匹配,但是如果随便翻转一个'('的话可能会导致序列出现负数,因此我们需要找到一个[L,N],里面所有的数都大于等于2,我们翻转第L-1个括号便可以( 因为L是大于等于2的而L-1小于等于2,所有L必定是‘(’ )
用线段树来维护这个序列,第一种情况维护f=A[i]-i,如果是‘)’f[i]将小于0,第二种情况维护区间最小值minx就可以
一般来说数组开到maxn*3左右应该就可以了,但是这道题蜜汁re,开了maxn*4就过了,大概是我线段树写法的问题?
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define maxn 330000
using namespace std;
struct Tree
{
int l,r,date;
int minx,f;
}tree[maxn*4];
int lazy[maxn*4],s[maxn];
char str[maxn];
void push_up(int root)
{
tree[root].f=min(tree[root<<1].f,tree[root<<1|1].f);
tree[root].minx=min(tree[root<<1].minx,tree[root<<1|1].minx);
}
void build(int root,int l,int r)
{
tree[root].l=l;
tree[root].r=r;
if (l==r)
{
tree[root].f=s[l]-l;
tree[root].minx=s[l];
return;
}
int mid=(l+r)>>1;
build(root<<1,l,mid);
build(root<<1|1,mid+1,r);
push_up(root);
}
void push_down(int root)
{
if (lazy[root]!=0)
{
tree[root<<1].minx+=lazy[root];
tree[root<<1].f+=lazy[root];
lazy[root<<1]+=lazy[root];
tree[root<<1|1].minx+=lazy[root];
tree[root<<1|1].f+=lazy[root];
lazy[root<<1|1]+=lazy[root];
lazy[root]=0;
}
}
void update(int root,int l,int r,int p)
{
if (tree[root].l>=l && tree[root].r<=r)
{
tree[root].f+=p;
tree[root].minx+=p;
lazy[root]+=p;
return;
}
push_down(root);
int mid=(tree[root].l+tree[root].r)>>1;
if (l<=mid) update(root<<1,l,r,p);
if (r>mid) update(root<<1|1,l,r,p);
push_up(root);
}
int query1(int root)
{
if (tree[root].l==tree[root].r)
{
return tree[root].l;
}
push_down(root);
if (tree[root<<1].f<0) return query1(root<<1);
else return query1(root<<1|1);
}
int query2(int root)
{
if (tree[root].l==tree[root].r)
{
return tree[root].l;
}
push_down(root);
if (tree[root<<1|1].minx< 2) return query2(root<<1|1);
else return query2(root<<1);
}
int main()
{
int n,m;
while (scanf("%d%d",&n,&m)!=EOF)
{
scanf("%s",str+1);
memset(s,0,sizeof(s));
memset(tree,0,sizeof(tree));
memset(lazy,0,sizeof(lazy));
int len=strlen(str+1);
for (int i=1;i<=len;i++)
{
if (str[i]=='(')
s[i]=s[i-1]+1;
else
s[i]=s[i-1]-1;
}
build(1,1,len);
for (int i=0;i<m;i++)
{
int k;
scanf("%d",&k);
if (str[k]==')')
{
update(1,k,len,2);
str[k]='(';
int res=query2(1)+1;
update(1,res,len,-2);
str[res]=')';
printf("%d\n",res);
}
else
{
update(1,k,len,-2);
str[k]=')';
int res=query1(1);
update(1,res,len,2);
str[res]='(';
printf("%d\n",res);
}
}
}
}