CSU 1542 Flipping Parentheses(线段树)

来源:互联网 发布:不用网络调频收音机 编辑:程序博客网 时间:2024/05/21 21:31

1542: Flipping Parentheses

Time Limit: 5 Sec  Memory Limit: 256 MB
Submit: 289  Solved: 79
[Submit][Status][Web Board]

Description

Input

 

Output

 

Sample Input

6 3((()))431

Sample Output

221

HINT

 


题目大意:

给出一个长度为n的已经匹配的括号字符串,然后有Q次操作,每次操作会翻转一个括号,让你翻转最左边的某个括号使得整个字符串再次匹配。

解题思路:
首先特殊处理一下字符串:
对于字符串,定义一定tmpnum,tmpnum[0]=0,然后如果第i位是‘(’,tmpnum[i]=tmpnum[i-1]+1,反之-1.
那么就会变成
          ( ( (  ) ) )
           1  2  3  2  1  0

如果匹配,那么‘(’和‘)’的数量一定相等,即tmpnum[n]=0。

然后分情况讨论翻转的括号:

(1)如果是把第4、5位的‘)’翻转成‘(’,上述序列就变成了
          ( ( ( (  ) )
           1  2  3  4  3  2
          ( ( (  )(  )
           1  2  3  2  3  2

我们发现如果翻转第i位,且第i位是‘)’,翻转后的序列是[i,n]这个区间的值全部加2。反之如果是‘(’变为‘)’我们可以推出全部减2。如果要重新匹配,即把tmpnum[n]变为0,我们就要找到一个点k使得区间[k+1,n]的值全部大于等于2。在这里我们可以翻转2号。
所以对于把‘)’变为‘(’的情况,我们要找到最左边的一个k使得[k+1,n]这个区间的值全部大于等于2;

(2)如果是把‘(’变为‘)’
那么我们要找到最左边的一个‘(’,使得后面的值全部加2,这样一定是最优解。
那么如何找到最左边的‘(’呢?我们可以定义一个tmpdis[i]=tmpnum[i]-i。如果tmpdis[i]小于0,那第i位一定是‘)’。

所以我们的线段树需要维护2个值,minn和dis,minn对应的是上述的tmpnum序列,dis对应的是上述tmpdis序列。每次查询我们查询的是minn中最左边的位置k,要求[k+1,n]的minn值全部大于等于2,或者查询的是dis中最左边的位置k,要求dis[k]小于等于0。


参考代码:

#include<set>#include<map>#include<stack>#include<queue>#include<cmath>#include<vector>#include<cctype>#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;#define lson l,mid,cur<<1#define rson mid+1,r,cur<<1|1#define root 1,n,1const double eps=1e-10;const int INF=0x3f3f3f3f;const int MAXN=3e5+50;typedef long long LL; char s[MAXN];int n,m,minn[MAXN<<2],dis[MAXN<<2],flag[MAXN<<2],tmpnum[MAXN],tmpdis[MAXN]; void push_up(int cur){    minn[cur]=min(minn[cur<<1],minn[cur<<1|1]);    dis[cur]=min(dis[cur<<1],dis[cur<<1|1]);} void push_down(int cur){    if(flag[cur])    {        flag[cur<<1]+=flag[cur];        flag[cur<<1|1]+=flag[cur];        minn[cur<<1]+=flag[cur];        minn[cur<<1|1]+=flag[cur];        dis[cur<<1]+=flag[cur];        dis[cur<<1|1]+=flag[cur];        flag[cur]=0;    }} void build(int l,int r,int cur){    flag[cur]=0;    if(l==r)    {        minn[cur]=tmpnum[l];        dis[cur]=tmpnum[l]-l;        return ;    }    int mid=(l+r)>>1;    build(lson);    build(rson);    push_up(cur);} void update(int a,int b,int inc,int l,int r,int cur){    if(a<=l&&r<=b)    {        minn[cur]+=inc;        dis[cur]+=inc;        flag[cur]+=inc;        return ;    }    push_down(cur);    int mid=(l+r)/2;    if(a<=mid)        update(a,b,inc,lson);    if(b>mid)        update(a,b,inc,rson);    push_up(cur);} int query1(int l,int r,int cur)//查询最左边的使得dis[k]小于等于0的k{    if(l==r)        return l;    push_down(cur);    int mid=(l+r)>>1;    if(dis[cur<<1]<0)        return query1(lson);    else        return query1(rson);} int query2(int l,int r,int cur)//查询使得[k+1,n]全部大于1的k{    if(l==r)        return l;    push_down(cur);    int mid=(l+r)>>1;    if(minn[cur<<1|1]<2)        return query2(rson);    else        return query2(lson);} int main(){#ifndef ONLINE_JUDGE    freopen("in.txt","r",stdin);#endif // ONLINE_JUDGE    while(scanf("%d%d",&n,&m)!=EOF)    {        scanf("%s",s+1);        int sum=0;        for(int i=1;i<=n;i++)        {            sum+=s[i]=='('?1:-1;            tmpdis[i]=sum-i;            tmpnum[i]=sum;        }        build(root);        for(int i=1;i<=m;i++)        {            int t;            scanf("%d",&t);            if(s[t]=='(')            {                s[t]=')';                update(t,n,-2,root);                t=query1(root);                s[t]='(';                update(t,n,2,root);                //puts(s+1);            }            else            {                s[t]='(';                update(t,n,2,root);                t=query2(root)+1;                s[t]=')';                update(t,n,-2,root);                //puts(s+1);            }            printf("%d\n",t);        }    }    return 0;}


2 0
原创粉丝点击