码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2019-12-29 16:30:38      阅读:58      评论:0      收藏:0      [点我收藏+]

标签:最大的   就是   strlen   树根   std   printf   name   左移   res   

题意:给你一串指令集,当某个指令为$``L"$时,表示鼠标的光标向左移动一个单位$($如果已经位于最左边,则不移动$)$,当指令为$``R"$时,表示将光标像右移动一个单位,其他的字符$($只有小写字母和左括号、右括号$)$都表示将当前光标指向的字符更改为输入的字符,对于每个指令,输出一个数,如果所得到的文本中括号序列合法,则是输出当前文本最大的括号嵌套层数,括号序列不合法则输出$-1$

思路:用$1$表示左括号,$-1$表示右括号,$0$表示其他字符,用一个线段树维护三个值:区间和$w$,区间最大前缀和$imax$,区间最小前缀和$imin$。对于任意一个合法的括号序列,需要满足以下两个条件:

  • 左括号和右括号的数量相等,即$w=0$
  • 括号序列的任意前缀和都大于等于$0$,即$imin \ge 0$

而对于一个合法的括号序列,括号的最大嵌套层数就是区间最大前缀和$imax$,需要维护一个单点修改和区间查询的线段树,但由于每次查询的区间都是$[1,n]$,线段树根节点表示的区间正好是$[1,n]$,所以只用维护一个单点修改的线段树,输入小写字母和左括号、右括号时,将光标位置上的值改为对应的值,同时更新区间和,区间最大前缀和,区间最小前缀和,具体更新如下:

  • 区间和$=$左区间和$+$右区间和
  • 最小前缀和$=min($左区间最小前缀和$,$左区间区间和$+$右区间最小前缀和$)$
  • 最大前缀和$=max($左区间最大前缀和$,$左区间区间和$+$右区间最大前缀和$)$

更新后判断$[1,n]$的括号序列是否合法,不合法输出$-1$,合法则直接输出区间$[1,n]$中$imax$的值

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
 
using namespace std;
 
const int N = 1000010;
 
struct node {
    int l, r, w;
    int imin, imax;
};
 
node tree[4 * N];
int n, res[N];
char s[N];
 
void build(int k, int lef, int rig)
{
    tree[k].l = lef, tree[k].r = rig;
    if (tree[k].l == tree[k].r) {
        tree[k].w = tree[k].imin = tree[k].imax = 0;
        return;
    }
    int mid = (lef + rig) / 2;
    build(k * 2, lef, mid);
    build(k * 2 + 1, mid + 1, rig);
    tree[k].w = tree[k * 2].w + tree[k * 2 + 1].w;
    tree[k].imax = max(tree[k * 2].imax, tree[k * 2 + 1].imax);
    tree[k].imin = max(tree[k * 2].imin, tree[k * 2 + 1].imin);
}
 
void change_point(int k, int x, int y)
{
    if (tree[k].l == tree[k].r) {
        tree[k].w = y;
        return;
    }
    int mid = (tree[k].l + tree[k].r) / 2;
    if (x <= mid) change_point(2 * k, x, y);
    else change_point(2 * k + 1, x, y);
    tree[k].w = tree[k * 2].w + tree[k * 2 + 1].w;
    tree[k].imax = max(tree[k * 2].imax, tree[k * 2].w + tree[k * 2 + 1].imax);
    tree[k].imin = min(tree[k * 2].imin, tree[k * 2].w + tree[k * 2 + 1].imin);
}
 
int main()
{
    scanf("%d%s", &n, s + 1);
    build(1, 1, n);
    int cur = 1, len = strlen(s + 1);
    for (int i = 1; i <= len; i++) {
        if (( == s[i]) change_point(1, cur, 1);
        else if () == s[i]) change_point(1, cur, -1);
        else if (L == s[i]) {
            if (cur >= 2) cur--;
        }
        else if (R == s[i]) cur++;
        else change_point(1, cur, 0);
        if (0 != tree[1].w || 0 != tree[1].imin) res[i] = -1;
        else res[i] = tree[1].imax;
    }
    for (int i = 1; i <= len; i++) {
        printf("%d", res[i]);
        printf(i == len ? "\n" : " ");
    }
    return 0;
}

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

标签:最大的   就是   strlen   树根   std   printf   name   左移   res   

原文地址:https://www.cnblogs.com/zzzzzzy/p/12115114.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!