题解 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) << "\n";
        else{
            int v = read();
            tree_modify(x, y, v);
        }
    }
#ifdef LOCAL
    Debug("\nMy Time: %.3lfms\n", (double)clock() / CLOCKS_PER_SEC);
#endif
    return 0;
}

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

posted @ 2018-12-02 23:28  yizimi  阅读(156)  评论(0编辑  收藏  举报