题目链接: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); } } } }