首页 > 其他分享 >CF1149C Tree Generator™

CF1149C Tree Generator™

时间:2024-08-13 16:55:12浏览次数:12  
标签:le Generator int max sum Tree 括号 区间 CF1149C

题意

\(n\) 个点,\(m\) 个询问。

给你一棵树的括号序列,输出它的直径。

有 \(m\) 次询问,每次询问表示交换两个括号,输出交换两个括号后的直径(保证每次操作后都为一棵树)

输出共 \(m + 1\) 行。

\(3 \le n \le 100\,000,1 \le q \le 100\,000\)

—— 洛谷翻译。

思路

我们不难想到,一个括号如果匹配,那么以它为根的子树中所有结点已经全部访问完毕。

所以我们可以想到,一段区间中没有匹配的括号个数就是一条路径的长度。

所以一条直径所对应的括号序列一定是由若干右括号接若干左括号构成的。

然后我们很套路地将 ) 赋值为 \(-1\),将 ( 赋值为 \(1\)。

如果一段区间除了)就是两两匹配的括号,那么这一段的和为右括号数量的相反数。

如果一段区间除了(就是两两匹配的括号,那么这一段的和为左括号数量。

那么对于一段区间 \([l, r]\),如果 \([l, k]\) 除了 ) 就是两两匹配的括号,\([k + 1, r]\) 除了 ( 就是两两匹配的括号,那么 \([l, r]\) 对应的路径长度就是右括号数量 + 左括号数量(不包括匹配括号),即 \(sum(k + 1, r) - sum(l, k)\),这个就是直径,如果分割点不在 \(k\),而在 \(p\),那么有一些匹配的括号会使得答案少 2,所以 \(sum(p + 1, r) - sum(l, p) \le sum(k + 1, r) - sum(l, k)\),所以我们只要保证 \(k\) 最大,\(sum(k + 1, r) - sum(l, k)\) 一定是直径长度。

那么我们可以用线段树来在一段含 \(n\) 个数字的数列 \(a\) 中查找 \(\max\limits_{1 \le l \le r \le n}\max\limits_{l\le k< r} sum(k + 1, r) - sum(l, k)\)。

线段树维护 8 个信息:

  1. 一个区间的和 sum
  2. 一个区间前缀的最大和 lsum_max
  3. 一个区间前缀的最小和 lsum_min
  4. 一个区间后缀的最大和 rsum_max
  5. 一个区间后缀的最小和 rsum_min
  6. 一个区间后一段减去前一段的最大和(\(\max\limits_{l < g \le k \le r}sum(g, k) - sum(l, g - 1)\))lans
  7. 一个区间后一段减去前一段的最大和(\(\max\limits_{l \le k < g \le r}sum(g, r) - sum(k, g - 1)\))rans
  8. 结果,\(\max\limits_{1 \le l \le r \le n}\max\limits_{l\le k< r} sum(k + 1, r) - sum(l, k)\)
    ans

image

怎么维护请看代码(懒得写了)。

代码

#include <bits/stdc++.h>

using namespace std;

const int N = 200010;

int n, q, a[N];

struct node {
    int sum;
    int lsum_max, rsum_max;
    int lsum_min, rsum_min;
    int lans, rans;
    int ans;
} tr[N << 2];

node init(int x) {
    node nd;
    nd.sum = x;
    nd.lsum_max = nd.rsum_max = max(x, 0);
    nd.lsum_min = nd.rsum_min = min(x, 0);
    nd.lans = nd.rans = nd.ans = 1;
    return nd;
}

node pushup(node left, node right) {
    node res;
    res.sum = left.sum + right.sum;
    res.lsum_max = max(left.lsum_max, left.sum + right.lsum_max);
    res.rsum_max = max(right.rsum_max, right.sum + left.rsum_max);
    res.lsum_min = min(left.lsum_min, left.sum + right.lsum_min);
    res.rsum_min = min(right.rsum_min, right.sum + left.rsum_min);
    res.lans = max(max(left.lans, right.lans - left.sum), right.lsum_max + 2 * left.rsum_max - left.sum);
    res.rans = max(max(right.rans, right.sum + left.rans), right.sum - left.rsum_min - 2 * right.lsum_min);
    res.ans = max(max(left.ans, right.ans), max(right.lans - left.rsum_min, left.rans + right.lsum_max));
    return res;
}

void build(int u, int l, int r) {
    if (l == r) {
        tr[u] = init(a[l]);
        return;
    }

    int mid = l + r >> 1;
    build(u << 1, l, mid);
    build(u << 1 | 1, mid + 1, r);
    tr[u] = pushup(tr[u << 1], tr[u << 1 | 1]);
}

void modify(int u, int l, int r, int x) {
    if (l == r) {
        tr[u] = init(a[x]);
        return;
    }
    int mid = l + r >> 1;
    if (x <= mid) modify(u << 1, l, mid, x);
    else modify(u << 1 | 1, mid + 1, r, x);
    tr[u] = pushup(tr[u << 1], tr[u << 1 | 1]);
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    cin >> n >> q;
    n = (n - 1) * 2;
    for (int i = 1; i <= n; i++) {
        char c;
        cin >> c;
        if (c == '(') a[i] = 1;
        else a[i] = -1;
    }

    build(1, 1, n);
    cout << tr[1].ans << '\n';
    while (q--) {
        int x, y;
        cin >> x >> y;
        swap(a[x], a[y]);
        if (a[x] != a[y]) modify(1, 1, n, x), modify(1, 1, n, y);
        cout << tr[1].ans << '\n';
    }
    return 0;
}

标签:le,Generator,int,max,sum,Tree,括号,区间,CF1149C
From: https://www.cnblogs.com/Yuan-Jiawei/p/18357320

相关文章

  • clickhouse_mergeTree
    MergeTree类型Clickhouse中最强大的表引擎当属MergeTree(合并树)引擎及该系列(*MergeTree)中的其他引擎。MergeTree系列的引擎被设计用于插入极大量的数据到一张表当中。数据可以以数据片段的形式一个接着一个的快速写入,数据片段在后台按照一定的规则进行合并。相比在插入时不......
  • QSortFilterProxyModel和QTreeView排序功能
    1、需求,创建一个树有多层结构,同一层按照插入顺序逆序排列; ui.treeView->setHeaderHidden(true);//treewidget头标题是否显示,此处隐藏标题//ui.treeWidget->header()->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);ui.treeView->header()->s......
  • TI 生成 TPG 流程 Test Pattern Generator
    TI生成TPGTestPatternGenerator1.主要作用:生成各种预定义的图形和模式用来检查CSI接口的图像传输质量调试和验证使用TPG生成的测试图形可以方便地验证接口的正确性和稳定性2.代码中的体现staticconstchar*constub960_tpg_qmenu[]={ "Disabled", "1vertical......
  • el-tree 组件自定义样式 最后一级flex,其余级别正常block
    先上需求的效果图el-tree的样式一般全都是block换行的,如下图先分析一下,1.树结构的级别是不确定的,但是样式上要求最后一个层级需要横着排列,其余竖着排,超出需要换行2.如何找到每一个数据项的最后一级呢?3.找到之后怎么办?ok,then,1.先通过插槽吧,因为这样咱们可以自定义最后一......
  • BINARY-SEARCH-TREES(二叉搜索树)
        一颗二叉搜索树是以一颗二叉树来组织的。除了数据之外,每个结点还包含属性left,right和p,它们分别指向结点的左孩子,右孩子和双亲。如果某个孩子结点和父结点不存在,则相应属性值为NULL。根结点是树中唯一父指针为NULL的结点。    二叉搜索树对任何结点x,其左子......
  • F - Perfect Matching on a Tree
    原题链接分析考虑两个点对\((a,b),(x,y)\)如果点对\((a,b)\)的路径与点对\((x,y)\)的路径不存在共同的点,那么此时我们交换\(a,x\),则有点对\((x,b),(a,y)\)此时两个点对的路径相交,且\(dis(x,b)+dis(a,y)\gtdis(a,b)+dis(x,y)\)所以,最后的答案一定是一条路径与其他所......
  • Qt自定义TreeWidget,实现展开折叠按钮在右侧,且一条竖直线上对齐
    效果如下:图片随便找的,可能需要调下样式,代码复制可用,留给有需要的人。 #ifndefCustomTreeWidget_h__#defineCustomTreeWidget_h__#include<QTreeWidget>#include<QPushButton>classCCustomTreeWidget:publicQTreeWidget{ Q_OBJECTpublic: CCustomTreeW......
  • Dsu On Tree
    前置知识:树链剖分的一些东西会打暴力DSUOnTree是啥中文名:树上启发式合并/静态链分治先考虑启发式合并是啥:说到启发式合并,那么常见的就是并查集了。我们将小的集合合并到大的集合中,就可以变成\(O(n\logn)\)神奇让高度小的树成为高度较大的树的子树,这个优化可......
  • Windows图形界面(GUI)-MFC-C/C++ - 树形视图(Tree Control) - CTreeCtrl
    公开视频-> 链接点击跳转公开课程博客首页-> ​​​链接点击跳转博客主页目录树形视图(TreeControl)-CTreeCtrl创建和初始化添加和删除项获取和设置项属性操作项项选择变化项双击项展开示例代码树形视图(TreeControl)-CTreeCtrl创建和初始化Subclas......