Gym 240084E - Correct Bracket Sequence Editor - [线段树]

题目链接:https://codeforces.com/gym/240084/problem/E

题意:

给出一个已经匹配的括号串,给出起始的光标位置(光标总是指向某个括号)。

有如下操作:

  1、往左移动一下光标;

  2、往左移动一下光标;

  3、删除当前光标指向的括号,以及和它匹配的那个括号,以及这两个括号之间的所有括号。

要求你给出在做完所有操作后的括号串。

题解:

用线段树维护,每个括号是否存在,存在记为 $1$,被删掉了记为 $0$。

然后我们只需要实现:①区间求和、②区间赋值、③根据 $k$ 求最小的 $x$ 满足在区间 $[1,x]$ 上求和正好等于 $k$。

移动光标可以通过①和③来完成;删除可以通过②来删除,删除完之后的光标移动依然可以靠①③完成。

时间复杂度是 $O(n + m \log n)$,分别是建树和 $m$ 次操作的时间复杂度。

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=5e5+5;
int n,m,p;
char s[maxn];
char op[maxn];

#define ls (rt<<1)
#define rs (rt<<1|1)
struct Node{
    int l,r;
    int val;
    bool del;
    void update() {
        val=0, del=1;
    }
}o[maxn<<2];
void pushdown(int rt)
{
    if(o[rt].del)
    {
        o[ls].update();
        o[rs].update();
        o[rt].del=0;
    }
}
inline void pushup(int rt) {
    o[rt].val=o[ls].val+o[rs].val;
}
void build(int rt,int l,int r)
{
    o[rt].l=l, o[rt].r=r;
    o[rt].del=0;
    if(l==r)
    {
        o[rt].val=1;
        return;
    }
    int mid=(l+r)>>1;
    build(ls,l,mid);
    build(rs,mid+1,r);
    pushup(rt);
}
void del(int rt,int st,int ed)
{
    if(st<=o[rt].l && o[rt].r<=ed)
    {
        o[rt].update();
        return;
    }
    pushdown(rt);
    int mid=(o[rt].l+o[rt].r)>>1;
    if(st<=mid) del(ls,st,ed);
    if(mid<ed) del(rs,st,ed);
    pushup(rt);
}
int sum(int rt,int st,int ed)
{
    if(st>ed) return 0;
    if(st<=o[rt].l && o[rt].r<=ed) return o[rt].val;
    pushdown(rt);
    int mid=(o[rt].l+o[rt].r)>>1;
    int res=0;
    if(st<=mid) res+=sum(ls,st,ed);
    if(mid<ed) res+=sum(rs,st,ed);
    pushup(rt);
    return res;
}
int idx(int rt,int k)
{
    if(o[rt].l==o[rt].r) return 1;
    pushdown(rt);
    if(o[ls].val>=k) return idx(ls,k);
    else return (o[ls].r-o[ls].l+1)+idx(rs,k-o[ls].val);
}

stack<int> S;
int bro[maxn];

int main()
{
    cin>>n>>m>>p;
    scanf("%s",s+1);
    for(int i=1;i<=n;i++)
    {
        if(s[i]==‘(‘) S.push(i);
        if(s[i]==‘)‘) bro[S.top()]=i, bro[i]=S.top(), S.pop();
    }

    scanf("%s",op+1);

    build(1,1,n);
    for(int q=1;q<=m;q++)
    {
        if(op[q]==‘L‘)
        {
            p=idx(1,sum(1,1,p)-1);
        }
        if(op[q]==‘R‘)
        {
            p=idx(1,sum(1,1,p)+1);
        }
        if(op[q]==‘D‘)
        {
            int st=min(p,bro[p]);
            int ed=max(p,bro[p]);
            del(1,st,ed);
            if(sum(1,ed+1,n)>0)
                p=idx(1,sum(1,1,ed)+1);
            else
                p=idx(1,sum(1,1,st-1));
        }
    }

    for(int i=1;i<=n;i++)
    {
        if(sum(1,i,i)>0) printf("%c",s[i]);
    }
}

原文地址:https://www.cnblogs.com/dilthey/p/10503952.html

时间: 2024-07-30 14:01:02

Gym 240084E - Correct Bracket Sequence Editor - [线段树]的相关文章

Codeforces Round #350 (Div. 2) E. Correct Bracket Sequence Editor 线段树模拟

E. Correct Bracket Sequence Editor Recently Polycarp started to develop a text editor that works only with correct bracket sequences (abbreviated as CBS). Note that a bracket sequence is correct if it is possible to get a correct mathematical express

Codeforces Round #350 (Div. 2) E. Correct Bracket Sequence Editor

E. Correct Bracket Sequence Editor Recently Polycarp started to develop a text editor that works only with correct bracket sequences (abbreviated as CBS). Note that a bracket sequence is correct if it is possible to get a correct mathematical express

cf670E Correct Bracket Sequence Editor

Recently Polycarp started to develop a text editor that works only with correct bracket sequences (abbreviated as CBS). Note that a bracket sequence is correct if it is possible to get a correct mathematical expression by adding "+"-s and "

Codeforces 670E Correct Bracket Sequence Editor (list模拟)

题意 给出一个合法的小括号序列,然后有三种操作: L 光标左移 R 光标右移 D 删除当前位置括号并他的对应括号,两括号中间的也一起删除. 输出操作后的序列. 思路 list直接模拟就好了,这题主要考察的也就是list的操作吧. list的删除也确实是个坑,注意光标移动出界之后别忘了向左移动一下. 代码 #include <stdio.h> #include <string.h> #include <iostream> #include <algorithm>

CodeForces 670E Correct Bracket Sequence Editor

链表,模拟. 写一个双向链表模拟一下过程. #pragma comment(linker, "/STACK:1024000000,1024000000") #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<map> #include<set> #include&

Codeforces Round #603 (Div. 2) E. Editor 线段树

E. Editor The development of a text editor is a hard problem. You need to implement an extra module for brackets coloring in text. Your editor consists of a line with infinite length and cursor, which points to the current character. Please note that

HDOJ--4893--Wow! Such Sequence!【线段树+单点、区间更新】

链接:http://acm.hdu.edu.cn/showproblem.php?pid=4893 题意:给你一个长度n的数列,初始都为0,有三种操作,第一种给第k个位置的数加d,第二种是查询区间 [l , r] 的总和,第三种是使区间 [l , r] 的值改为离它最近的那个斐波那契数的值. 我刚开始用sum数组存储节点的值,第三种操作是个区间更新,但是区间更新的值不一样,我就想当然的搜到最底部的节点来处理更新,果断T了.后来想了想,其实可以在节点上再加一个信息,就是这个值下次进行第三种操作要变

HDU Wow! 4893 Such Sequence!(线段树)

HDU 4893 Wow! Such Sequence! 题目链接 题意:给定一个序列,3种操作,单点添加值,查询区间和,把区间和变成最接近的婓波那契数 思路:线段树,就是第三个操作麻烦,就在结点添加一个值,标记它区间是不是都是婓波那契数了,然后修改区间的时候,如果区间是了就不用修改,如果不是就继续往后一层推即可 代码: #include <cstdio> #include <cstring> #include <cstdlib> #define lson(x) ((x

HDU 4893 Wow! Such Sequence! 水线段树

思路: 线段树走起.. 写完这题就退役T^T 单点更新的时候直接找到这个点的最近fib,然后维护当前和 和 fib的和 #include<stdio.h> #include<string.h> #include<iostream> #include<math.h> #include<algorithm> #include<queue> #include<map> #include<set> #include&l