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次操作

每次操作将某个括号反转,问将哪个括号反转能使字符串的括号再次匹配,位置要取最左端符合条件的。

可以利用前缀和 比如(())那么前缀和分别就是1,2,1,0。观察到,平衡时前缀和都是等于0的。

通过前缀和,我们可以发现规律:

将一个‘(‘翻转成‘)‘会使得从当前位置开始到字符串最后的前缀和都会减2

如果将‘)‘翻转成‘(‘,同理,此位置开始以后的所有前缀和都要加2

而如果减去了2,那如何增加2抵消掉之前的影响,得到最后的后缀和为零

而减去2的话肯定是‘(‘翻转成‘)‘,那么如何加一个数抵消掉‘)‘的影响

如果是将p点翻转的话,肯定是从[1,p],找一个‘)‘,将‘)‘翻转成‘(‘

有没有发现规律,如果是‘(‘翻转成‘)‘,则是在之前的区间将‘)‘翻转成‘(‘,那么将‘)‘翻转成‘(‘时,就是往后,找一个‘(‘将其‘(‘翻转成‘)‘

维护该区间的最小值即可,只要最小值不小于2,那么该区间的所有值都不会小于2

提供一个朋友的详解地址,说的很好:http://blog.csdn.net/qwb492859377/article/details/47357553

/*
Author: 2486
Memory: 32700 KB		Time: 760 MS
Language: C++		Result: Accepted
VJ RunId: 4340427		Real RunId: 149963
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>

using namespace std;
#define lson rt << 1, l, mid
#define rson rt << 1|1, mid + 1, r
#define root 1, 1, n
const int MAXN = 5e5 + 5;
const int INF = 0x3f3f3f3f;

int sum[MAXN << 2];
int Min[MAXN << 2],col[MAXN << 2],val[MAXN << 2];
int S,n,m;
char str[MAXN];

void pushup_1(int rt) {
    sum[rt] = min(sum[rt << 1], sum[rt << 1|1]);
}

void build(int rt, int l, int r) {
    col[rt] = 0;
    if(l == r) {
        val[rt] = (str[l] == '(' ? 1 : -1);
        S += val[rt];
        Min[rt] = S;
        sum[rt] = val[rt] == 1 ? INF : l;
        return;
    }
    int mid = (l + r) >> 1;
    build(lson);
    build(rson);
    pushup_1(rt);
    Min[rt] = min(Min[rt << 1], Min[rt << 1|1]);
}

int update_1(int p, int rt, int l, int r) {
    if(l == r) {
        int tmp = val[rt];
        val[rt] *= -1;
        sum[rt] = tmp == 1 ? p : INF;
        return tmp;
    }
    int mid = (l + r) >> 1, ret;
    if(p <= mid) ret = update_1(p, lson);
    if(p > mid) ret = update_1(p, rson);
    pushup_1(rt);
    return ret;
}
void pushdown(int rt) {
    if(col[rt]) {
        col[rt << 1] += col[rt];
        col[rt << 1|1] += col[rt];
        col[rt] = 0;
    }
}

void pushup_2(int rt) {
    Min[rt] = min(Min[rt << 1] + col[rt << 1], Min[rt << 1|1] + col[rt << 1|1]);
}

void update_2(int L, int R, int c,int rt, int l, int r) {
    if(L <= l && r <= R) {
        col[rt] += c;
        return;
    }
    pushdown(rt);
    int mid = (l + r) >> 1;
    if(L <= mid) update_2(L, R, c, lson);
    if(R > mid) update_2(L, R, c, rson);
    pushup_2(rt);
}

int query(int rt, int l,int r) {
    if(Min[rt] + col[rt] >= 2) return l;
    if(l == r) return r + 1;
    pushdown(rt);
    int mid = (l + r) >> 1;
    int ret;
    if(Min[rt << 1|1] + col[rt << 1|1] >= 2) ret = query(lson);
    else ret = query(rson);
    pushup_2(rt);
    return ret;
}

int main() {
    int p;
    while(~scanf("%d %d",&n,&m)) {
        scanf("%s",str+1);
        S = 0;
        build(root);
        while(m--) {
            scanf("%d",&p);
            int tmp = update_1(p, root);
            update_2(p, n, tmp * (-2), root);
            printf("%d\n",p = (tmp == 1 ? sum[1] : query(root)));
            update_1(p, root);
            update_2(p, n, tmp * 2, root);
        }
    }
    return 0;
}

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

时间: 2024-08-24 10:22:22

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

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次操作,每次操作会翻转一个括号,让你翻转最

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