我是靠谱客的博主 聪明菠萝,最近开发中收集的这篇文章主要介绍[LCT 刷题][树链信息维护] P2486 [SDOI2011]染色,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

题目思路

题目要求维护树上序列不同颜色段数,涉及到树链的性质,因此考虑用LCT解决。

但是我们可以发现:颜色段计数跟线段树有点不一样。我们需要对树链上的每条边进行转换,将两个端点共色的边设为 0 0 0,异色的设为 1 1 1,那么最终答案就变成了树链上的和。

但是我们发现这个题涉及了动态修改,因此我们需要单独的维护每条边,即在LCT的Splay节点上维护每个节点 x x x自身的颜色 x c xc xc,其左儿子的颜色 l c lc lc,其右儿子的颜色 r c rc rc,然后考虑如何上传答案:

我们将上传分为三种情况讨论:
在这里插入图片描述

  1. 当前节点 x x x与其左右儿子都异色,由于Splay节点 x x x左儿子在原树的深度一定小于 x x x x x x右儿子深度大于 x x x,即 x x x一定充当了分割点的作用,因此新增了2个颜色段。如果初始每个点都视为一个颜色段,那么就是新增了1个颜色段;

  2. 当前节点 x x x与其左儿子或右儿子异色,此时共色节点构成同一颜色段,异色节点构成新段,因此新增1个颜色段;如果初始每个点都视为一个颜色段,那么就是新增了0个颜色段;

  3. 当前节点 x x x与其左右儿子都同色,显然三个点在原树上共属一个颜色段,那么新增0个颜色段,如果初始每个点都视为一个颜色段,那么就是新增了-1个颜色段;

需要注意的是,在push_up前需要保证当前节点的懒标记已经 p u s h _ d o w n push_down push_down完毕。

Code

#include <bits/stdc++.h>
#pragma gcc optimize("O2")
#pragma g++ optimize("O2")
#define int long long
#define endl 'n'
using namespace std;

const int N = 2e5 + 10, MOD = 1e9 + 7;

namespace LCT{
    struct Info{
        int ans, lc, rc, xc, ctag;
        void init_color(int c) { lc = rc = xc = c, ans = 1; }
    }tree[N];
    int ch[N][2], f[N], tag[N];
    #define ls ch[x][0]
    #define rs ch[x][1]

    inline void push_reverse(int x) { swap(ls, rs), swap(tree[x].lc, tree[x].rc), tag[x] ^= 1; }

    inline void push_color(int x, int c) { tree[x].init_color(c); tree[x].ctag = c; }

    inline void push_down(int x) {
        if(tree[x].ctag) {
            push_color(ls, tree[x].ctag);
            push_color(rs, tree[x].ctag);
            tree[x].ctag = 0;
        }
        if(tag[x]) {
            if(ls) push_reverse(ls);
            if(rs) push_reverse(rs);
            tag[x] = 0;
        }
    }

    inline void push_up(int x) {
        push_down(ls), push_down(rs);
        tree[x].lc = ls ? tree[ls].lc : tree[x].xc;
        tree[x].rc = rs ? tree[rs].rc : tree[x].xc;
        if(ls && rs) tree[x].ans = tree[ls].ans + tree[rs].ans + 1 - (tree[ls].rc == tree[x].xc) - (tree[rs].lc == tree[x].xc);
        else if(ls) tree[x].ans = tree[ls].ans + (tree[ls].rc != tree[x].xc);
        else if(rs) tree[x].ans = tree[rs].ans + (tree[rs].lc != tree[x].xc);
        else tree[x].ans = 1;
    }

    #define get(x) (ch[f[x]][1] == x)                        
    #define isRoot(x) (ch[f[x]][0] != x && ch[f[x]][1] != x)

    void rotate(int x) {
        int y = f[x], z = f[y], k = get(x);
        if(!isRoot(y)) ch[z][ch[z][1] == y] = x;
        ch[y][k] = ch[x][!k], f[ch[x][!k]] = y;
        ch[x][!k] = y, f[y] = x, f[x] = z;
        push_up(y); push_up(x);
    }

    void update(int x) {
        if(!isRoot(x)) update(f[x]);
        push_down(x);
    }

    void splay(int x) {
        update(x);
        for(int fa = f[x]; !isRoot(x); rotate(x), fa = f[x]) {
            if(!isRoot(fa)) rotate(get(fa) == get(x) ? fa : x);
        }
        push_up(x);
    }

    int access(int x) {
        int p;
        for(p = 0; x; x = f[p = x]) splay(x), rs = p, push_up(x);
        return p;
    }

    void makeRoot(int x) { access(x), splay(x), push_reverse(x); }

    int findRoot(int x) {
        access(x), splay(x);
        while(ch[x][0]) push_down(x), x = ch[x][0];
        splay(x);
        return x;
    }

    void split(int x, int y) {
        makeRoot(x);
        access(y), splay(y);
    }

    void link(int x, int y) {
        makeRoot(x);
        if(findRoot(y) != x) f[x] = y;
    }

    void cut(int x, int y) {
        makeRoot(x);
        if(findRoot(y) == x && f[y] == x && !ch[y][0]) {
            f[y] = ch[x][1] = 0;
            push_up(x);
        }
    }
}

inline void solve(){
    int n, m; cin >> n >> m;
    for(int i = 1, c = 0; i <= n; i++) cin >> c, LCT::tree[i].init_color(c);
    for(int i = 1; i < n; i++) {
        int u, v; cin >> u >> v;
        LCT::link(u, v);
    }

    while(m--) {
        char op; cin >> op;
        if(op == 'C') {
            int u, v, c; cin >> u >> v >> c;
            LCT::split(u, v); 
            LCT::push_color(v, c);
        } else if(op == 'Q') {
            int u, v; cin >> u >> v;
            LCT::split(u, v);
            cout << LCT::tree[v].ans << endl;
        }
    }

}

signed main(){
    ios_base::sync_with_stdio(false), cin.tie(0);
    cout << fixed << setprecision(12);
    int t = 1; // cin >> t;
    while(t--) solve();
    return 0;
}

最后

以上就是聪明菠萝为你收集整理的[LCT 刷题][树链信息维护] P2486 [SDOI2011]染色的全部内容,希望文章能够帮你解决[LCT 刷题][树链信息维护] P2486 [SDOI2011]染色所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(38)

评论列表共有 0 条评论

立即
投稿
返回
顶部