zoukankan      html  css  js  c++  java
  • [CF380C] Sereja and Brackets

    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;
        }
    }
    
  • 相关阅读:
    固定sql语句传参批量查询数据库脚本
    超多行数据纵向编辑
    takes 3 positional arguments but 4 were given错误
    使用PMD进行代码审查(转)
    WebADI应用到Office 2016 64-bit
    SVN 提交代码时强制加入注释内容
    DOCKER初体验
    "make_path" is not exported by the File::Path modul
    perl 调用shell脚本
    scp 上传文件到多个服务器节点
  • 原文地址:https://www.cnblogs.com/mollnn/p/14077665.html
Copyright © 2011-2022 走看看