首页 > 其他 > 详细

[CF380C] Sereja and Brackets - 线段树

时间:2020-12-03 10:02:41      阅读:40      评论:0      收藏:0      [点我收藏+]

Description

给定一个括号序列,每次询问一个区间,求这个区间的所有子序列中,合法括号序列的最大长度。

Solution

考虑线段树,对于一个区间,其内部相互匹配后,一定会剩下若干的左括号堆积在右侧,若干的右括号堆积在左侧。

合并区间时,左边剩余的左括号和右边剩余的右括号会相互消去一部分。

#include <bits/stdc++.h>
using namespace std;

string seq_str;
int seq_len, num_query;

struct SegmentTree
{
    struct Node
    {
        int left_bracket;  // 右边堆积的左括号数目
        int right_bracket; // 左边堆积的右括号数目
    };

    friend Node operator+(const Node &lhs, const Node &rhs)
    {
        return {lhs.left_bracket + rhs.left_bracket - min(lhs.left_bracket, rhs.right_bracket),
                lhs.right_bracket + rhs.right_bracket - min(lhs.left_bracket, rhs.right_bracket)};
    }

    Node *node;
    int seg_len;

    SegmentTree(int n_)
    {
        seg_len = n_;
        node = new Node[4 * seg_len + 5];
    }

    void pushup(int p)
    {
        node[p] = node[p * 2] + node[p * 2 + 1];
    }

    void build(int p, int l, int r, string &str)
    {
        if (l == r)
        {
            node[p] = {str[l - 1] == ‘(‘, str[l - 1] == ‘)‘};
        }
        else
        {
            build(p * 2, l, (l + r) / 2, str);
            build(p * 2 + 1, (l + r) / 2 + 1, r, str);
            pushup(p);
        }
    }

    void Build(string &str)
    {
        build(1, 1, seg_len, str);
    }

    Node query(int p, int l, int r, int ql, int qr)
    {
        if (l > qr || r < ql)
            return {0, 0};
        if (l >= ql && r <= qr)
            return node[p];
        return query(p * 2, l, (l + r) / 2, ql, qr) + query(p * 2 + 1, (l + r) / 2 + 1, r, ql, qr);
    }

    Node Query(int ql, int qr)
    {
        return query(1, 1, seg_len, ql, qr);
    }

    int QueryAns(int ql, int qr)
    {
        auto tmp = Query(ql, qr);
        return (qr - ql + 1 - tmp.left_bracket - tmp.right_bracket);
    }
};

int main()
{
    ios::sync_with_stdio(false);

    cin >> seq_str;
    cin >> num_query;

    seq_len = seq_str.length();

    SegmentTree segment_tree(seq_len);
    segment_tree.Build(seq_str);

    for (int i = 1; i <= num_query; i++)
    {
        int l, r;
        cin >> l >> r;

        cout<<segment_tree.QueryAns(l,r)<<endl;
    }
}

[CF380C] Sereja and Brackets - 线段树

原文:https://www.cnblogs.com/mollnn/p/14077665.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!