• CSU 1809


    题目链接:http://acm.csu.edu.cn/csuoj/problemset/problem?pid=1809

    Bobo has a balanced parenthesis sequence P=p 1 p 2…p n of length n and q questions.
    The i-th question is whether P remains balanced after p ai and p bi  swapped. Note that questions are individual so that they have no affect on others.
    Parenthesis sequence S is balanced if and only if:
    1.  S is empty;
    2.  or there exists balanced parenthesis sequence A,B such that S=AB;
    3.  or there exists balanced parenthesis sequence S' such that S=(S').

    Input

    The input contains at most 30 sets. For each set:
    The first line contains two integers n,q (2≤n≤10 5,1≤q≤10 5).
    The second line contains n characters p 1 p 2…p n.
    The i-th of the last q lines contains 2 integers a i,b i (1≤a i,b i≤n,a i≠b i).

    Output

    For each question, output " Yes" if P remains balanced, or " No" otherwise.

    Sample Input

    4 2
    (())
    1 3
    2 3
    2 1
    ()
    1 2

    Sample Output

    No
    Yes
    No

    题意:

    现在给出长度为n的一串圆括号串,保证是平衡的括号串;

    再给出q个查询,每个查询有两个值a,b,代表询问交换P[a]和P[b],会不会使得括号串变得不平衡。

    题解:

    首先,我们定义一个preSum数组,代表了这括号序列的前缀和,遇到一个'('就加上1,遇到一个')'就减去1;

    这样一来,该括号序列为平衡序列 $Leftrightarrow$ preSum[n]==0,且对于$forall$i=1~n都有preSum[i]≥0;

    那么我们有以下三种情况:

    1. P[a]==P[b],这样情况显然交换一下和原来没有区别,显然是保持平衡的;
    2. P[a]=')'且P[b]='(',这种情况下,preSum[1]~preSum[a-1]不会有任何变动,preSum[a]~preSum[b-1]都会$+=2$,preSum[b]~preSum[n]也不会有任何变动,这样一来,交换后产生的新的括号序列,依然满足preSum[n]==0,且对于$forall$i=1~n都有preSum[i]≥0,那么显然该括号序列还是平衡序列;
    3. P[a]='('且P[b]=')',这种情况下,preSum[1]~preSum[a-1]不会有任何变动,preSum[a]~preSum[b-1]都会$-=2$,preSum[b]~preSum[n]不会有任何变动,那么显然关键就在preSum[a]~preSum[b-1]上了,我们知道一旦有一个preSum[i]<0,这个括号序列就不平衡了,所以我们必须保证preSum[a]~preSum[b-1]都大于等于2才行。

    所以,我们可以使用线段树或者RMQ维护preSum[]数组的区间最小值,对每次查询只要查询出[a,b]区间内preSum[i]的最小值有没有比2大就可以了。

    AC代码:

    ①线段树:

    #include<cstdio>
    #include<cstring>
    #include<vector>
    using namespace std;
    typedef long long LL;
    
    const int maxn=1e5+10;
    const int INF=0x3f3f3f3f;
    
    int n,q;
    char str[maxn];
    int preSum[maxn];
    
    struct Node{
        int l,r;
        int val;
    }node[4*maxn];
    void pushup(int root)
    {
        node[root].val=min(node[root*2].val,node[root*2+1].val);
    }
    void build(int root,int l,int r)
    {
        node[root].l=l; node[root].r=r;
        if(l==r) node[root].val=preSum[l];
        else
        {
            int mid=l+(r-l)/2;
            build(root*2,l,mid);
            build(root*2+1,mid+1,r);
            pushup(root);
        }
    }
    int query(int root,int st,int ed)
    {
        if(ed<node[root].l || node[root].r<st) return INF;
        if(st<=node[root].l && node[root].r<=ed) return node[root].val;
        else return min(query(root*2,st,ed),query(root*2+1,st,ed));
    }
    
    int main()
    {
        while(scanf("%d%d",&n,&q)!=EOF)
        {
            scanf("%s",str+1);
    
            preSum[0]=0;
            for(int i=1;i<=n;i++) preSum[i]=preSum[i-1]+(str[i]=='('?1:-1);
    
            build(1,1,n);
            for(int i=1,a,b;i<=q;i++)
            {
                scanf("%d%d",&a,&b);
                if(a>b) swap(a,b);
    
                if( str[a]==str[b] || (str[a]==')' && str[b]=='(') ) printf("Yes
    ");
                else if(query(1,a,b-1)>=2) printf("Yes
    ");
                else printf("No
    ");
            }
        }
    }

    ②RMQ:

    #include<cstdio>
    #include<cstring>
    #include<vector>
    #include<cmath>
    using namespace std;
    typedef long long LL;
    
    const int maxn=1e5+10;
    const int INF=0x3f3f3f3f;
    
    int n,q;
    char str[maxn];
    int preSum[maxn];
    
    struct _RMQ{
        int Mnum[maxn][20]; //int(log(maxn)/log(2.0))
        void init(int num[])
        {
            for(int i=1;i<=n;i++) Mnum[i][0]=num[i];
            int j_max=(log(n)/log(2));
            for(int j=1;j<=j_max;j++)
            {
                for(int i=1;i<=n;i++)
                {
                    if(i+(1<<j)-1 <= n)
                        Mnum[i][j]=min(Mnum[i][j-1],Mnum[i+(1<<(j-1))][j-1]);
                }
            }
        }
        int query(int l,int r)
        {
            int k=log(r-l+1)/log(2);
            return min(Mnum[l][k],Mnum[r-(1<<k)+1][k]);
        }
    }RMQ;
    
    int main()
    {
        while(scanf("%d%d",&n,&q)!=EOF)
        {
            scanf("%s",str+1);
    
            preSum[0]=0;
            for(int i=1;i<=n;i++) preSum[i]=preSum[i-1]+(str[i]=='('?1:-1);
    
            RMQ.init(preSum);
            for(int i=1,a,b;i<=q;i++)
            {
                scanf("%d%d",&a,&b);
                if(a>b) swap(a,b);
    
                if( str[a]==str[b] || (str[a]==')' && str[b]=='(') ) printf("Yes
    ");
                else if(RMQ.query(a,b-1)>=2) printf("Yes
    ");
                else printf("No
    ");
            }
        }
    }
  • 相关阅读:
    Aizu 0033
    Aizu 0118
    【思维】贪心+细节——cf1361B
    【思维】构造+凸包+向量叉积——LEETCODE 游乐园的迷宫
    【思维】三元环计数+鸽笼定理/贪心——LEETCODE 游乐园的游览计划 好题
    dp+线性筛——LEETCODE切分数组
    【经典】带障碍的铺砖块——LEETCODE 覆盖
    【思维】树形dp+构造——leetcode二叉树任务调度
    【思维】状压dp—— 2020 联想杯 M
    【思维】建图+排列组合+预处理+最短路—— 2020 联想杯 E
  • 原文地址:https://www.cnblogs.com/dilthey/p/8987284.html
Copyright © 2020-2023  润新知