• 数据结构大师


    数据结构大师

    时间限制: 1 Sec 内存限制: 128 MB
    [提交] [状态]

    题目描述

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

    输入

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

    输出

    对于每个询问输出一行表示答案。

    样例输入 Copy

    4 1
    (())
    2 4

    样例输出 Copy

    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的维护显然,减去已经匹配成功的即可;

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn=1e6+5;
    char s[maxn];
    #define ls (rt<<1)
    #define rs ((rt<<1)+1)
    int n,m;
    struct node {
        node() {};
    
        node(int l, int r, int mx) : l(l), r(r), mx(mx) {};
        int l, r, mx;
    }t[maxn<<2];
    void build(int rt,int l,int r) {
        if (l == r) {
            t[rt].l = s[l] == '(';
            t[rt].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[rt].mx = t[ls].mx + x + t[rs].mx;
        t[rt].l = t[ls].l - x + t[rs].l;
        t[rt].r = t[ls].r + t[rs].r - x;
    }
    node ask(int rt,int l,int r,int x,int y) {
        if (x <= l && r <= y)
            return t[rt];
        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 {
            node lx = ask(ls, l, mid, x, y);
            node rx = ask(rs, mid + 1, r, x, y);
            int use = min(lx.l, rx.r);
            return node(lx.l + rx.l - use, lx.r + rx.r - use, lx.mx + rx.mx + use);
        }
    }
    int main() {
        scanf("%d%d", &n, &m);
        scanf("%s", s + 1);
        build(1, 1, n);
        while (m--) {
            int l, r;
            scanf("%d%d", &l, &r);
            printf("%d
    ", ask(1, 1, n, l, r).mx * 2);
        }
        return 0;
    }
    
  • 相关阅读:
    C++ 将对象写入文件 并读取
    IronPython fail to add reference to WebDriver.dll
    How to Capture and Decrypt Lync Server 2010 TLS Traffic Using Microsoft Tools
    .net code injection
    数学系学生应该知道的十个学术网站
    Difference Between Currency Swap and FX Swap
    Swift开源parser
    谈谈我对证券公司一些部门的理解(前、中、后台)[z]
    JDK8记FullGC时候Metaspace内存不会被垃圾回收
    JVM源码分析之JDK8下的僵尸(无法回收)类加载器[z]
  • 原文地址:https://www.cnblogs.com/Accpted/p/12689195.html
Copyright © 2020-2023  润新知