• 题解 P2486 【[SDOI2011]染色】


    主要思路:树链剖分 + 线段树

    一看就知道是棵树,可以通过树链剖分后维护。

    颜色就相当于点权,强烈暗示树链剖分。

    所以重点就落在了如何维护区间颜色块数?

    1 1 2 2 3 3 3 2
    

    我们可以这样考虑:

    我们考虑小区间与小区间是不是可以合并。

    如:

    1 1 2 2    3 3 3 2
    

    假如我们已经知道这左右两段的左右端点和各自的颜色块数,我们可以想象一下对接这两个区间,如果左半段右端点和右半段左端点是一样的话,合起来的区间就会比原来两段区间中颜色块数之和少一个颜色块。

    合并的问题解决了,那如何算其中一个区间的颜色块数?

    我们和刚刚的方法相似,就是把这个区间分开,然后按照刚刚的办法合并,合并时把同块的减掉,,,

    如果一直分下去,,是不是和什么数据结构有点类似,,,

    线段树!

    我们可以拿线段树模拟出来刚刚的过程,,,

    于是这道题就就这么愉快的结束了

    我不会告诉你我一个读入写错了交了一页的0分代码

    代码:

    #include <algorithm>
    #include <cmath>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <ctime>
    #include <iostream>
    #include <map>
    #include <queue>
    #include <set>
    #include <stack>
    #include <string>
    #include <vector>
    using namespace std;
    #define go(i, j, n, k) for (int i = j; i <= n; i += k)
    #define fo(i, j, n, k) for (int i = j; i >= n; i -= k)
    #define rep(i, x) for (int i = h[x]; i; i = e[i].nxt)
    #define mn 100010
    #define inf 2147483647
    #define ll long long
    #define ld long double
    #define fi first
    #define se second
    #define root 1, n, 1
    #define lson l, m, rt << 1
    #define rson m + 1, r, rt << 1 | 1
    #define bson l, r, rt
    //#define LOCAL
    #define mod 
    #define Debug(...) fprintf(stderr, __VA_ARGS__)
    inline int read(){
        int f = 1, x = 0;char ch = getchar();
        while (ch > '9' || ch < '0'){if (ch == '-')f = -f;ch = getchar();}
        while (ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
        return x * f;
    }
    //This is AC head above...
    int n, m;
    struct edge{
        int v, nxt;
    } e[mn << 1];
    int p, h[mn];
    inline void add(int a,int b){
        e[++p].nxt = h[a], h[a] = p, e[p].v = b;
    }
    int w[mn], dep[mn], sze[mn], fa[mn], son[mn], id[mn], ptn[mn], b[mn], top[mn], cnt;
    // Array
    struct tree{
        int l, r, lc, rc, sum, col;
        tree(int _l = 0, int _r = 0, int _lc = 0, int _rc = 0, int _sum = 0, int _col = 0)
            : l(_l), r(_r), lc(_lc), rc(_rc), sum(_sum), col(_col) {}
    };
    struct segmenttree{
        tree z[mn << 2];
        inline void update(int rt){
            z[rt].sum = z[rt << 1].sum + z[rt << 1 | 1].sum;
            if(z[rt<<1].rc == z[rt<<1|1].lc)
                z[rt].sum--;
            z[rt].lc = z[rt << 1].lc;
            z[rt].rc = z[rt << 1 | 1].rc;
        }
        inline void color(int l,int r,int rt,int v){
            z[rt].lc = z[rt].rc = v;
            z[rt].sum = 1;
            z[rt].col = v;
        }
        inline void push_col(int l,int r,int rt){
            if(z[rt].col){
                int m = (l + r) >> 1;
                color(lson, z[rt].col);
                color(rson, z[rt].col);
                z[rt].col = 0;
            }
        }
        inline void build(int l,int r,int rt){
            if(l==r){
                z[rt].lc = z[rt].rc = b[l];
                z[rt].sum = 1;
                return;
            }
            int m = (l + r) >> 1;
            build(lson);
            build(rson);
            update(rt);
        }
        inline void modify(int l,int r,int rt,int nowl,int nowr,int v){
            if(nowl<=l && r<=nowr){
                color(bson, v);
                return;
            }
            int m = (l + r) >> 1;
            push_col(bson);
            if(nowl<=m)
                modify(lson, nowl, nowr, v);
            if(m<nowr)
                modify(rson, nowl, nowr, v);
            update(rt);
        }
        inline tree query(int l,int r,int rt,int nowl,int nowr){
            if(nowl<=l && r<=nowr){
                return z[rt];
            }
            int m = (l + r) >> 1;
            push_col(bson);
            if(nowl<=m){
                if(m<nowr){
                    tree res, ltr = query(lson, nowl, nowr), rtr = query(rson, nowl, nowr);
                    res.sum = ltr.sum + rtr.sum + (ltr.rc == rtr.lc ? -1 : 0);
                    res.lc = ltr.lc, res.rc = rtr.rc;
                    return res;
                }else{
                    return query(lson, nowl, nowr);
                }
            }else{
                return query(rson, nowl, nowr);
            }
        }
    } tr;
    // line segment tree
    void dfs1(int x,int f,int deep){
        dep[x] = deep;
        fa[x] = f;
        sze[x] = 1;
        int maxson = -1;
        rep(i,x){
            int v = e[i].v;
            if(v==f)
                continue;
            dfs1(v, x, deep + 1);
            sze[x] += sze[v];
            if(maxson<sze[v])
                maxson = sze[v], son[x] = v;
        }
    }
    void dfs2(int x,int topf){
        id[x] = ++cnt;
        ptn[id[x]] = x;
        b[id[x]] = w[x];
        top[x] = topf;
        if(!son[x])
            return;
        dfs2(son[x], topf);
        rep(i,x){
            int v = e[i].v;
            if(v==fa[x]||v==son[x])
                continue;
            dfs2(v, v);
        }
    }
    // DFS
    inline void tree_modify(int x,int y,int v){
        while(top[x] != top[y]){
            if(dep[top[x]] < dep[top[y]])
                swap(x, y);
            tr.modify(root, id[top[x]], id[x], v);
            x = fa[top[x]];
        }
        if(dep[x] > dep[y])
            swap(x, y);
        tr.modify(root, id[x], id[y], v);
    }
    inline int tree_query(int x,int y){
        int sum = 0, lxx = 0, sxy = 0;
        while(top[x] != top[y]){
            if(dep[top[x]] < dep[top[y]])
                swap(x, y), swap(lxx, sxy);
            tree res = tr.query(root, id[top[x]], id[x]);
            sum += res.sum;
            if(res.rc == lxx)
                sum--;
            lxx = res.lc;
            x = fa[top[x]];
        }
        if(dep[x] > dep[y])
            swap(x, y), swap(lxx, sxy);
        tree res = tr.query(root, id[x], id[y]);
        sum += res.sum;
        if(res.lc == lxx)
            sum--;
        if(res.rc == sxy)
            sum--;
        return sum;
    }
    int main(){
        n = read(), m = read();
        go(i, 1, n, 1) w[i] = read();
        go(i, 1, n - 1, 1){
            int a = read(), b = read();
            add(a, b), add(b, a);
        }
        dfs1(1, 1, 1);
        dfs2(1, 1);
        tr.build(root);
        go(i, 1, m, 1){
            char c;
            cin >> c;
            int x = read(), y = read();
            if(c=='Q')
                cout << tree_query(x, y) << "
    ";
            else{
                int v = read();
                tree_modify(x, y, v);
            }
        }
    #ifdef LOCAL
        Debug("
    My Time: %.3lfms
    ", (double)clock() / CLOCKS_PER_SEC);
    #endif
        return 0;
    }
    
    

    第十四次写题解,希望可以帮助大家理解这道题线段树维护颜色块的原理

    NOIP2018并不是结束,而是开始
  • 相关阅读:
    一个简单粗暴的爬虫
    Linux 目录结构
    python 部署 Restful web
    JVM 运行时数据区总结 栈 堆 堆大小配置总结
    成都法律援助申请流程
    JavaEE error整理(不断更新)
    ehcache.xml 属性大全
    SpringMVC 构建Restful风格 及问题处理
    Http Content-Type
    Redis 教程 Java工程师学习知识点
  • 原文地址:https://www.cnblogs.com/yizimi/p/10056270.html
Copyright © 2020-2023  润新知