首页 > 其他 > 详细

2014-2015 ACM-ICPC, Asia Tokyo Regional Contest - G - Flipping Parentheses

时间:2020-10-22 22:29:45      阅读:27      评论:0      收藏:0      [点我收藏+]

2014-2015 ACM-ICPC, Asia Tokyo Regional Contest - G - Flipping Parentheses


做这个题可以熟悉一下线段树的应用。
首先设‘(‘值为1,‘)‘值为1,维护一个前缀和,那么字符串平衡的条件便是到任意位置的前缀和都大于0(左括号数量大于等于右括号数量)并且左右括号数量相等。

当把\(pos\)位置的左括号变为右括号时,相当于把\([pos, n]\)区间内的前缀和都减2(1变成-1)。那么根据上述平衡条件,我们只需要把最左边一个右括号转为左括号。这个可以用\(set\)维护,每发现一个右括号就把它的位置\(insert\)到set里,用的时候只要使用\(upper\_bound()\)函数就能得到我们需要的位置,再\(erase()\)即可。

当把\(pos\)位置的右括号变为左括号时,相当于把\([pos, n]\)区间内的前缀和都加2(-1变成1)。虽然仍然满足第一个平衡条件,但为了保持左右括号数目相等,我们仍需翻转一个左括号,而翻转\(id\)位置的左括号会使\([id, n]\)区间内的前缀和减2,所以我们要找的位置id必须满足\([id, n]\)区间上的最小值大于等于2(不然前缀和会有小于0)。区间最小值用线段树维护,id用二分查找。


代码
#include <bits/stdc++.h>
typedef long long ll;
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 300005;
int a[maxn];
int n, m;
set<int> l;
struct node{
    int l, r;
    ll Min;
    ll addv;
}tree[4*maxn];
void build(int o, int l, int r)
{
    tree[o].l = l;
    tree[o].r = r;
    if(l==r){
        tree[o].Min = a[l];
        return;
    }
    int mid = (l+r)>>1;
    build(o*2, l, mid);
    build(o*2+1, mid+1, r);
    tree[o].Min = min(tree[o*2].Min, tree[o*2+1].Min);
}
void spread(int o)
{
    if(tree[o].addv){
        tree[o*2].addv += tree[o].addv;
        tree[o*2+1].addv += tree[o].addv;
        tree[o*2].Min += tree[o].addv;
        tree[o*2+1].Min += tree[o].addv;
        tree[o].addv = 0;
    }
}
void change(int o, int l, int r, int k){
    if(tree[o].l>=l && tree[o].r<=r){
        tree[o].Min += k;
        tree[o].addv += k;
        return;
    }
    spread(o);
    int mid = (tree[o].l+tree[o].r)>>1;
    if(l<=mid) change(o*2, l, r, k);
    if(r>mid) change(o*2+1, l, r, k);
    tree[o].Min = min(tree[o*2].Min, tree[o*2+1].Min);
    return;
}
ll ask(int o, int l, int r)
{
    if(tree[o].l>=l && tree[o].r<=r){
        return tree[o].Min;
    }
    spread(o);
    ll res = INF;
    int mid = (tree[o].l+tree[o].r)>>1;
    if(l<=mid) res = min(res, ask(o*2, l, r));
    if(r>mid) res = min(res, ask(o*2+1, l, r));
    return res;
}
int main()
{
    #ifdef LOCAL
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif
    cin >> n >> m;
    string s;
    cin >> s;
    for(int i=1; i<=n; i++){
        if(s[i-1]==‘(‘) a[i] = a[i-1]+1;
        else{
            a[i] = a[i-1]-1;
            l.insert(i);
        }
    }
    build(1, 1, n);
    for(int i=1; i<=m; i++){
        int q;
        cin >> q;
        if(s[q-1]==‘(‘){
            s[q-1] = ‘)‘;
            l.insert(q);
            change(1, q, n, -2);
            int pos = *l.upper_bound(0);
            change(1, pos, n, 2);
            l.erase(pos);
            s[pos-1] = ‘(‘;
            printf("%d\n", pos);
        }
        else{
            l.erase(q);
            s[q-1] = ‘(‘;
            change(1, q, n, 2);
            int ll = 1, rr = q;
            while(rr-ll>1){
                int mid = (ll+rr)>>1;
                if(ask(1, mid, q)>=2) rr=mid;
                else ll=mid;
            }
            s[rr-1] = ‘)‘;
            l.insert(rr);
            change(1, rr, n, -2);
            printf("%d\n", rr);
        }
    }
    return 0;
}

2014-2015 ACM-ICPC, Asia Tokyo Regional Contest - G - Flipping Parentheses

原文:https://www.cnblogs.com/DinoMax/p/13860915.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!