• 数据结构大师(求区间最长合法括号子序列)


    数据结构大师

    时间限制: 1 Sec 内存限制: 128 MB

    题目描述

    (Z)是个数据结构高手,这天他得到了一个由左括号和右括号组成的字符串。随之而来的是 (m) 次询问,对于第 (i) 次询问,小Z需要回答出这个字符串的第(l_i)(r_i) 个字符组成的字串中最长的合法括号子序列的长度。
    (Z)认为一个由左右括号组成的序列(A)合法,当且仅当其满足至少一个以下条件。
    (A)为空。

    • (A=(B))其中(B)是一个合法的括号序列。
    • (A=BC),其中(BC)都是合法的括号序列。
    • 比如合法的括号序列有((),()(),(()))等。

    输入

    第一行读入两个数字(n,m),分别表示长度和询问次数,接下来一行读入字符串(S)
    最后m行每行读入两个数(l_i,r_i),表示这次询问的区间。

    输出

    对于每个询问输出一行表示答案。
    样例输入
    4 1
    (())
    2 4
    样例输出
    2
    提示
    对于(30\%)的数据,满足(n,m<=500)
    对于(60\%)的数据,满足(n,m<=5000)
    对于(100\%)的数据,满足(1≤n≤10^6,1≤m≤10^5)

    思路:

    想到是区间问题自然想到了线段树,由于子序列不连续,我们用线段树维护'('和')'的数量记为(l,r)
    那么合并(ls)(rs)新增匹配(min(l,r)),设为(x),(若记(mx)为区间最长匹配对数)也即(t[p].mx+=x);
    同时我们累和(ls,rs)的长度,最终(t[p].mx=t[ls].mx+t[rs].mx+x);
    (l,r)的维护显然,减去已经匹配成功的即可;

    代码:

    //#pragma GCC optimize(2)
    //#pragma GCC optimize(3, "Ofast", "inline")
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    const int N=1e6+5;
    const ll mod=1e9+7;
    const double eps=1e-5;
    //const double pi=acos(-1);
     
    #define ls p<<1
    #define rs p<<1|1
     
    char s[N];
    struct seg
    {
        int l,r,mx;
    }t[N<<2];
    void build(int p,int l,int r)
    {
        if(l==r)
        {
            t[p].l=s[l]=='(';
            t[p].r=s[l]==')';
            return;
        }
        int mid=l+r>>1;
        build(ls,l,mid);
        build(rs,mid+1,r);
        int x=min(t[ls].l,t[rs].r);
        t[p].mx=t[ls].mx+x+t[rs].mx;
        t[p].l=t[ls].l-x+t[rs].l;
        t[p].r=t[ls].r+t[rs].r-x;
    }
    seg ask(int p,int l,int r,int x,int y)
    {
        if(x<=l&&r<=y)
            return t[p];
        int mid=l+r>>1;
        if(y<=mid)
            return ask(ls,l,mid,x,y);
        else if(x>mid)
            return ask(rs,mid+1,r,x,y);
        else
        {
            seg ans;
            seg lx=ask(ls,l,mid,x,y);
            seg rx=ask(rs,mid+1,r,x,y);
            int use=min(lx.l,rx.r);
            ans.mx=lx.mx+rx.mx+use;
            ans.l=lx.l+rx.l-use;
            ans.r=lx.r+rx.r-use;
            return ans;
        }
    }
    int main() {
    #ifndef ONLINE_JUDGE
        freopen("in.txt", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        cin.tie(0);
        int n,m;
        cin>>n>>m;
        cin>>(s+1);
        build(1,1,n);
        while(m--)
        {
            int l,r;
            cin>>l>>r;
            printf("%d
    ",ask(1,1,n,l,r).mx*2);
        }
        return 0;
    }
    
  • 相关阅读:
    poj 1141 Brackets Sequence (区间DP)
    算法:冒泡排序
    Learning English From Android Source Code:2 Ampersand
    泛泰A870刷4.4专用英文版非触摸CWM Recovery 6.0.4.8(三版通刷)
    Android Studio 那些事|Activity文件前标识图标显示为 j 而是 c
    HDU-4930 Fighting the Landlords 多校训练赛斗地主
    POJ 3211 Washing Clothes(01背包)
    C# winform ListView 的右键菜单的下级菜单的选项视情况禁用方法
    Android系统开发(4)——Autotools
    Android系统开发(3)——Makefile的编写
  • 原文地址:https://www.cnblogs.com/Suiyue-Li/p/12665036.html
Copyright © 2020-2023  润新知