CSU Problem 1809 Parenthesis(括号匹配,线段树,前缀和)——湖南省第十二届大学生计算机程序设计竞赛

此文章可以使用目录功能哟↑(点击上方[+])

 CSU Problem 1809 Parenthesis

Accept: 0    Submit: 0
Time Limit: 5 Sec    Memory Limit : 128 MB

 Problem Description

Bobo has a balanced parenthesis sequence P=p1 p2…pn of length n and q questions.

The i-th question is whether P remains balanced after pai and pbi 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 p1 p2…pn.

The i-th of the last q lines contains 2 integers ai,bi (1≤ai,bi≤n,ai≠bi).

 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

 Hint


 Problem Idea

解题思路:

【题意】
给你一串长度为n的已经成功匹配的括号串,q次询问

每次询问,问交换a,b两处的括号,该括号串是否仍能成功匹配

交换操作只对当前询问有效,即下一次询问开始,括号串还是最初给的那个括号串


【类型】
括号匹配,线段树,前缀和

【分析】

显然,对于位置i(∀i∈[1,n]),前i个括号中,只有左括号个数≥右括号个数,才能保证括号串成功匹配

我们不妨将左括号记为1,右括号记为−1,记[1,i]的前缀和为sum[i]

那么,我们由上可知,括号串成功匹配⇔sum[i]≥0(∀i∈[1,n])且sum[n]=0

因此,判断一个串是否是正确匹配的,只要去判断条件:sum[i]>=0(∀i∈[1,n])且sum[n]=0是否满足即可

回到本题,对于交换a,b两处的括号,分三种情况讨论:

⒈如果ch[a]=ch[b](即,交换的两处同时为'('或同时为')'),那么换了和没换一样,肯定是Yes;

⒉如果ch[a]≠ch[b],但ch[a]=−1(即a处为')'),那么肯定也是Yes,这相当于把sum[i],i∈[a,b−1]区间上的前缀和都+2,想想也知道,本来就已经成功匹配的括号串,还把'('往前挪了,这意味着对于位置i(∀i∈[1,n]),左括号个数更多了,那右括号必定能够匹配上;

⒊如果s[a]≠s[b],并且s[a]=1(即a处为'('),那么就要去判断区间[a,b−1]内前缀和的最小值是否≥2,如果是,那么就是Yes,否则就是No

因为对于区间[a,b-1],前缀和不仅少了1(a处的'('往后挪了),还多了-1(b处的')'移到前面来了),总共相当于减少了2

那为了满足"判断一个串是否是正确匹配的"的条件,那交换前该区间[a,b-1]内前缀和的最小值必须≥2

查询区间最小值可以用RMQ,也可以用线段树,前者时间复杂度为O(nlogn+q),后者时间复杂度为O(n+qlogn)

显然此题q和n的范围一致,所以两种做法都可以,本人采用的是线段树

【时间复杂度&&优化】
O(n+qlogn)

题目链接→CSU Problem 1809 Parenthesis

 Source Code

/*Sherlock and Watson and Adler*/
#pragma comment(linker, "/STACK:1024000000,1024000000")
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<queue>
#include<stack>
#include<math.h>
#include<vector>
#include<map>
#include<set>
#include<bitset>
#include<cmath>
#include<complex>
#include<string>
#include<algorithm>
#include<iostream>
#define eps 1e-9
#define LL long long
#define PI acos(-1.0)
#define bitnum(a) __builtin_popcount(a)
using namespace std;
const int N = 100005;
const int M = 2005;
const int inf = 1000000007;
const int mod = 1000003;
struct tree
{
    int left,right,Min;
}s[4*N];
char ch[N];
int sum[N];
void buildtree(int l,int r,int p)
{
    s[p].left=l,s[p].right=r;
    if(l==r)
    {
        s[p].Min=sum[l];
        return ;
    }
    int mid=(l+r)/2;
    buildtree(l,mid,p*2);
    buildtree(mid+1,r,p*2+1);
    s[p].Min=min(s[p*2].Min,s[p*2+1].Min);
}
int query(int l,int r,int p)
{
    if(s[p].left==l&&s[p].right==r)
        return s[p].Min;
    int mid=(s[p].left+s[p].right)/2;
    if(l>mid)
        return query(l,r,p*2+1);
    if(r<=mid)
        return query(l,r,p*2);
    return min(query(l,mid,p*2),query(mid+1,r,p*2+1));
}
int main()
{
    int n,q,i,a,b;
    while(~scanf("%d%d",&n,&q))
    {
        memset(sum,0,sizeof(sum));
        scanf("%s",ch+1);
        for(i=1;ch[i]!='\0';i++)
            sum[i]=sum[i-1]+(ch[i]=='('?1:-1);
        buildtree(1,n,1);
        for(i=0;i<q;i++)
        {
            scanf("%d%d",&a,&b);
            if(a>b)
                swap(a,b);
            if(ch[a]==ch[b]||ch[b]=='('||query(a,b-1,1)>=2)
                puts("Yes");
            else
                puts("No");
        }
    }
    return 0;
}
菜鸟成长记

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值