CodeForces - 1263E(线段树维护前缀和最值)

题意

https://vjudge.net/problem/CodeForces-1263E

您要设计一个只有一行的打字机,这一行的长度是无限大,一开始可以认为每个字符都是空。您的打字机有一个光标只指向一个字符,一开始指向最左侧的字符。

使用者有三种操作:

  • L 将光标向左移一格(当光标已经在最左侧时,忽略这次操作)

  • R 将光标向右移一格

  • 一个小写字符或者'(',')' 将当前字符替换为给定字符

您需要在每次操作后,判断这一行是否是合法括号序列(例如 (ahakioi) 就是合法的,(ige))(tscore 就是非法的),不是输出 -1,否则输出最多嵌套数(例如 ()(())()() 的最多嵌套数是 2,(()(()())())(()) 的最多嵌套数是 3)。

思路

看上去是个大模拟,实则是个线段树的技巧题。

用一个pos记录光标的位置。

记'('为1,')'为-1,其他字符为0,这样如果有某个前缀和<0(只用判断前缀和最小值<0即可),那么就不合法,或者所有加起来不等于0,也不合法。

单点更新,维护区间和sum,前缀和最小值mn,前缀和最大值mx。区间前缀和最小值和左右子树有关,比较左子树的前缀和最小值、右子树的前缀和最小值+左子树的区间和,用小的那个更新mn[rt],前缀和最大值同理。

那么在合法的情况下,前缀和的最大值即为最多嵌套数。

代码

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define ll long long
const int N=1e6+5;
const double eps=1e-8;
const double PI = acos(-1.0);
#define lowbit(x) (x&(-x))
int sum[N<<2],mn[N<<2],mx[N<<2],n;
void pushUp(int rt)
{
    sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    mn[rt]=min(mn[rt<<1],mn[rt<<1|1]+sum[rt<<1]);
    mx[rt]=max(mx[rt<<1],mx[rt<<1|1]+sum[rt<<1]);
}
void update(int L,int C,int l,int r,int rt)
{
    if(l==r)
    {
        sum[rt]=mn[rt]=mx[rt]=C;
        return;
    }
    int m=(l+r)>>1;
    if(L <= m) update(L,C,l,m,rt<<1);
    else       update(L,C,m+1,r,rt<<1|1);
    pushUp(rt);
}
int main()
{
    std::ios::sync_with_stdio(false);
    cin>>n;
    string s;
    cin>>s;
    int pos=1,r=1,ans=0;
    for(int i=0; i<n; i++)
    {
        char c=s[i];
        if(c=='R') pos++;
        else if(c=='L')
        {
            if(pos>1) pos--;
        }
        else
        {
            if(c=='(')
                update(pos,1,1,n,1);
            else if(c==')')
                update(pos,-1,1,n,1);
            else
                update(pos,0,1,n,1);
        }
        if(sum[1]!=0||mn[1]<0)
        {
            cout<<-1<<" ";
        }
        else
            cout<<mx[1]<<" ";
    }
    cout<<endl;
    return 0;
}

  

 

posted @ 2019-12-03 23:50  swineherd_MCQ  阅读(...)  评论(... 编辑 收藏