CodeForces - 1149C Tree Generator™

题意:

给定有 n n n 个点、边权为 1 1 1 的树的括号序列 s s s ∣ s ∣   = 2 n − 2 \mid s \mid ~= 2n - 2 s =2n2),再有 q q q 次操作,每次操作交换 s l , s r s_l, s_r sl,sr,每次操作后输出对应的树的直径。 ( n , q ≤ 1 0 5 ) (n, q \leq 10^5) (n,q105)

链接:

https://codeforces.com/contest/1149/problem/C

解题思路:

对于静态的树直径,有两次 d f s dfs dfs、树形 d p dp dp 的解法,这里括号序列也可以导出对应的求解方法,左括号对应深度 + 1 +1 +1,右括号对应深度减 − 1 -1 1,则预处理出前缀和即为深度数组 d e p dep dep d i s ( u , v ) = d e p [ u ] + d e p [ v ] − 2 ∗ d e p [ l c a ( u , v ) ] dis(u, v) = dep[u] + dep[v] - 2 * dep[lca(u, v)] dis(u,v)=dep[u]+dep[v]2dep[lca(u,v)],其中, d e p [ l c a ( u , v ) ] = min ⁡ { d e p [ l ] } dep[lca(u, v)] = \min\{dep[l]\} dep[lca(u,v)]=min{dep[l]} l l l u , v u, v u,v 任一对应括号位置之间的对应点,从左到右扫过去,维护 max ⁡ { d e p [ u ] } , max ⁡ { d e p [ u ] − 2 ∗ d e p [ l ] } , max ⁡ { d e p [ u ] + d e p [ v ] − 2 ∗ d e p [ l ] } \max\{dep[u]\}, \max\{dep[u] - 2 * dep[l]\}, \max\{dep[u] + dep[v] - 2 * dep[l]\} max{dep[u]},max{dep[u]2dep[l]},max{dep[u]+dep[v]2dep[l]},则可以 O ( n ) O(n) O(n) 得到树直径。

为了支持修改操作,使用线段树区间合并来动态维护,具体需要分别维护左右(前后缀)的对应信息。

参考代码:
#include<bits/stdc++.h>
 
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
#define sz(a) ((int)a.size())
#define pb push_back
#define lson (rt << 1)
#define rson (rt << 1 | 1)
#define gmid (l + r >> 1)
const int maxn = 2e5 + 5;
const int inf = 0x3f3f3f3f;
const int mod = 1e9 + 7;

char s[maxn];
int dep[maxn];
int n, q;

struct SegTree{

    int ans[maxn << 2], mxu[maxn << 2], mxl[maxn << 2], mxul[maxn << 2], mxlv[maxn << 2], add[maxn << 2];
    void pushUp(int rt){

        mxu[rt] = max(mxu[lson], mxu[rson]);
        mxl[rt] = max(mxl[lson], mxl[rson]);
        mxul[rt] = max(max(mxul[lson], mxul[rson]), mxu[lson] + mxl[rson]);
        mxlv[rt] = max(max(mxlv[lson], mxlv[rson]), mxl[lson] + mxu[rson]);
        ans[rt] = max(max(ans[lson], ans[rson]), max(mxu[lson] + mxlv[rson], mxul[lson] + mxu[rson]));
    }
    void build(int l, int r, int rt){

        add[rt] = 0;
        if(l == r){

            ans[rt] = 0;
            mxu[rt] = dep[l], mxl[rt] = -2 * dep[l], mxul[rt] = mxlv[rt] = -dep[l];
            return;
        }
        int mid = gmid;
        build(l, mid, lson);
        build(mid + 1, r, rson);
        pushUp(rt);
    }
    void pushDown2(int rt, int son){

        add[son] += add[rt];
        mxu[son] += add[rt];
        mxl[son] += -2 * add[rt];
        mxul[son] += -add[rt];
        mxlv[son] += -add[rt];
    }
    void pushDown(int rt){

        pushDown2(rt, lson);
        pushDown2(rt, rson);
        add[rt] = 0;
    }
    void update(int l, int r, int rt, int L, int R, int val){

        if(l >= L && r <= R){

            add[0] = val;
            pushDown2(0, rt);
            return;
        }
        int mid = gmid;
        pushDown(rt);
        if(L <= mid) update(l, mid, lson, L, R, val);
        if(R > mid) update(mid + 1, r, rson, L, R, val);
        pushUp(rt);
    }
} tr;

int main(){
 
    ios::sync_with_stdio(0); cin.tie(0);
    cin >> n >> q;
    cin >> s + 1;
    n = 2 * (n - 1);
    for(int i = 1; i <= n; ++i){

        dep[i] = dep[i - 1] + (s[i] == '(' ? 1 : -1);
    }
    tr.build(1, n, 1);
    cout << tr.ans[1] << "\n";
    while(q--){

        int l, r; cin >> l >> r;
        if(l > r) swap(l, r);
        if(s[l] == s[r]) continue;
        tr.update(1, n, 1, l, r - 1, s[l] == '(' ? -2 : 2);
        cout << tr.ans[1] << "\n";
        swap(s[l], s[r]);
    }
    return 0;
}
引用\[1\]中提到了一种树形动态规划的方法来解决CodeForces - 982C问题。在这个问题中,subtree指的是子连通块,而不是子树。为了使cnt_white - cnt_black尽可能大,可以使用两次树形动态规划来求解。第一次是自底向上的过程,维护一个dp数组,表示以每个节点为根的子树中的最大连通块。第二次是自顶向下的过程,处理自底向上过程中无法包含的树链所代表的子树。在第二次遍历中,需要维护一个sum变量,用于存储树链所代表的子树的贡献。根据ans\[u\]的正负,决定是否能对相邻的子节点做出贡献。如果ans\[u\]为正,则减去dp\[v\]就是树链所代表的子树的权值。最终,ans\[u\]代表包含节点u在内的子连通块的最大权值。\[1\] 问题: CodeForces - 982C 树形DP是什么问题?如何解决? 回答: CodeForces - 982C是一个树形动态规划问题。在这个问题中,需要求解子连通块的最大权值和,使得cnt_white - cnt_black尽可能大。解决这个问题的方法是使用两次树形动态规划。第一次是自底向上的过程,维护一个dp数组,表示以每个节点为根的子树中的最大连通块。第二次是自顶向下的过程,处理自底向上过程中无法包含的树链所代表的子树。在第二次遍历中,需要维护一个sum变量,用于存储树链所代表的子树的贡献。根据ans\[u\]的正负,决定是否能对相邻的子节点做出贡献。最终,ans\[u\]代表包含节点u在内的子连通块的最大权值。\[1\] #### 引用[.reference_title] - *1* *2* [CodeForces - 1324F Maximum White Subtree(树形dp)](https://blog.csdn.net/qq_45458915/article/details/104831678)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值