CSU 1542 Flipping Parentheses(线段树)

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
((()))
4
3
1

Sample Output

2
2
1

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,1
const 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;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-11 16:41:46

CSU 1542 Flipping Parentheses(线段树)的相关文章

CSU - 1542 Flipping Parentheses (线段树)

CSU - 1542 Flipping Parentheses Time Limit: 5000MS   Memory Limit: 262144KB   64bit IO Format: %lld & %llu Submit Status Description Input Output Sample Input 6 3 ((())) 4 3 1 Sample Output 2 2 1 Hint 题意:先给出一个符合括号匹配的字符串,然后Q次操作 每次操作将某个括号反转,问将哪个括号反转能使字

HDU 1542 Atlantis (线段树求矩阵覆盖面积)

题意:给你n个矩阵求覆盖面积. 思路:看了别人的结题报告 给定一个矩形的左下角坐标和右上角坐标分别为:(x1,y1).(x2,y2),对这样的一个矩形,我们构造两条线段,一条定位在x1,它在y坐标的区间是[y1,y2],并且给定一个cover域值为1:另一条线段定位在x2,区间一样是[y1,y2],给定它一个cover值为-1.根据这样的方法对每个矩形都构造两个线段,最后将所有的线段根据所定位的x从左到右进行排序 #include <iostream> #include <stdio.h

HDU 1542 Atlantis(线段树扫描线+离散化求面积的并)

Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 11551    Accepted Submission(s): 4906 Problem Description There are several ancient Greek texts that contain descriptions of the fabled

HDU - 1542 扫描线入门+线段树离散化

扫描线算法+线段树维护简介: 像这种求面积的并集的题目,就适合用扫描线算法解决,具体来说就是这样 类似这种给出点的矩形的对角的点的坐标,然后求出所有矩形面积的交集的问题,可以采用扫描线算法解决.图如下,我们要求红色部分的面积: 我们可以通过一条叫扫描线的东西解决问题.具体来说: 我们首先给自己一条线,这条可以我称之为标准线(棕色线表示) 从上往下(从下往上也行)我们把每个矩形用一个四元组表示了l,r,h,f  也就是说,把一个矩形用上下两条边表示,l,r分别是x1,x2,而h则是y坐标,f代表这

HDU 1542 Atlantis(线段树扫描线&#183;面积并)

题意  给你一些矩形的左下和右上的坐标  求这些矩形的面积并 最基础的扫描线  理解了就是个水题了  先看一些图吧                                恩  看完了有什么感觉没有  那些红色的线就可以当作传说中的扫描线  就像从左到右扫描嘛  可以发现  矩形有竖直边的地方就有这些线  这些线把把拼在一起的矩形切成了一个个的小矩形  我们把这些小矩形的面积加起来不就是要求的面积吗 那么现在这些小矩形的面积怎么求呢  长乘宽嘛  长是什么  两条红线之间的距离  恩  我

CSU 1453: 平衡序列 学会线段树后必做

http://acm.csu.edu.cn/OnlineJudge/problem.php?id=1453. 题目:给定一个大小为100000的数组,里面的数字最大也是100000.现在叫你求出一段子序列,使得他们任意两个数差的绝对值都不能超过k 其实这题的关键是数字的范围,不超过100000,这样的话 ,就可以用线段树整段覆盖了.记dp[i]为以这个数字为结尾的,最长的LIS的多少,开始的时候dp[i]=0,用线段树把他覆盖了.每次插入一个数a[i]的时候,都去找[a[i]-k,a[i]+k]

HDU 1542 Atlantis 线段树+离散化+扫描线

题意:给出一些矩形的最上角坐标和右下角坐标,求这些矩形的面积并. NotOnlySuccess 线段树专辑中扫描线模板题,弱智的我对着大大的代码看了一下午才搞懂. 具体见思路见注释=.= #include <cstdio> #include <cstring> #include <algorithm> #include <vector> #define lson rt<<1,l,mid #define rson rt<<1|1,mid

CSU 1110线段树

C - RMQ with Shifts Time Limit:1000MS     Memory Limit:131072KB     64bit IO Format:%lld & %llu Submit Status Practice CSU 1110 Appoint description:  System Crawler  (2015-03-10) Description In the traditional RMQ (Range Minimum Query) problem, we ha

hdu 1542 线段树+扫描线

啦啦啦~继续学算法 题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1542 Atlantis Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 7349    Accepted Submission(s): 3231 Problem Description There are several