SDOI_2011染色

Problems Website

  • SDOI_2011染色

    Solution

  • 又是一道熟练剖分的好题,区别是这一次的线段树要维护的信息有所不同,要维护4个东西:$num$(区间内不同颜色的数量)、$lc$(区间最左端的颜色)、$rc$(区间最右端的颜色)、$tag$(染色标记),在$pushup$时要注意,如果左儿子的$rc$等于右儿子的$lc$,则父亲的$num$等于他们的$num$之和$-1$,因为有重合的颜色。
  • 还有一点,在执行$Q$操作时也要判重,我们设$lc$为当前链的左端点的颜色,$rc$为当前链右端点的颜色,$pos1$为当前要往上跳的路径\上次的终点颜色,$pos2$为另一条路径\上一次的终点颜色,在往跳同一条链时,如果$pos1==rc$,则计量数$—$,在同一条链时,如果$lc==pos1$、$rc==pos2$,同样要减计量数。
  • 原因:当出现上述情况时,明显是颜色重合,所以要减。

    Code

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define gc getchar()
    #define pc(x) putchar(x)
    #define re register
    typedef long long ll;
    const int Maxn = 1e5 + 10;
    inline ll sc() {
    ll xx = 0, ff = 1; char cch = gc;
    while(!isdigit(cch)) {
    if(cch == '-') ff = -1; cch = gc;
    }
    while(isdigit(cch)) {
    xx = (xx << 1) + (xx << 3) + (cch ^ '0'); cch = gc;
    }
    return xx * ff;
    }
    inline ll out(ll x) {
    if(x < 0) pc('-'), x = -x;
    if(x >= 10)
    out(x / 10);
    pc(x % 10 + '0');
    }
    struct node {
    ll next, to;
    }t[Maxn << 1];
    struct LST {
    ll num, tags, lc, rc;
    }lst[Maxn << 2];
    ll n, m, cnt, pos1, pos2, lc, rc;
    ll a[Maxn], head[Maxn], dep[Maxn], son[Maxn], fa[Maxn], siz[Maxn], top[Maxn], rid[Maxn], id[Maxn];
    inline void ADD(ll from, ll to) {
    t[++cnt].next = head[from];
    t[cnt].to = to;
    head[from] = cnt;
    }
    inline void dfs1(ll now, ll Fa) {
    dep[now] = dep[Fa] + 1;
    fa[now] = Fa;
    siz[now] = 1;
    for(re int i = head[now]; i; i = t[i].next) {
    ll to = t[i].to;
    if(to == Fa) continue;
    dfs1(to, now);
    siz[now] += siz[to];
    if(siz[son[now]] < siz[to])
    son[now] = to;
    }
    }
    inline void dfs2(ll now, ll topf) {
    top[now] = topf;
    id[now] = ++cnt;
    rid[cnt] = now;
    if(!son[now]) return;
    dfs2(son[now], topf);
    for(re int i = head[now]; i; i = t[i].next) {
    ll to = t[i].to;
    if(to == son[now] || to == fa[now]) continue;
    dfs2(to, to);
    }
    }
    inline void pushup(ll k) {
    lst[k].num = lst[k << 1].num + lst[k << 1 | 1].num;
    if(lst[k << 1].rc == lst[k << 1 | 1].lc) --lst[k].num;
    lst[k].lc = lst[k << 1].lc;
    lst[k].rc = lst[k << 1 | 1].rc;
    }
    inline void build(ll k, ll l, ll r) {
    if(l == r) {
    lst[k].lc = lst[k].rc = a[rid[l]];
    lst[k].num = 1;
    return;
    }
    ll mid = l + r >> 1;
    build(k << 1, l, mid), build(k << 1 | 1, mid + 1, r);
    pushup(k);
    }
    inline void pushdown(ll k, ll l, ll r) {
    if(!lst[k].tags) return;
    lst[k << 1].lc = lst[k << 1 | 1].lc = lst[k << 1].rc = lst[k << 1 | 1].rc = lst[k << 1].tags = lst[k << 1 | 1].tags = lst[k].tags;
    lst[k << 1].num = lst[k << 1 | 1].num = 1;
    lst[k].tags = 0;
    }
    inline void modify(ll k, ll l, ll r, ll x, ll y, ll z) {
    if(x <= l && r <= y) {
    lst[k].lc = lst[k].rc = lst[k].tags = z;
    lst[k].num = 1;
    return ;
    }
    pushdown(k, l, r);
    ll mid = l + r >> 1;
    if(x <= mid) modify(k << 1, l, mid, x, y, z);
    if(y > mid) modify(k << 1 | 1, mid + 1, r, x, y, z);
    pushup(k);
    }
    inline ll query(ll k, ll l, ll r, ll x, ll y) {
    if(x <= l && r <= y) {
    if(x == l) lc = lst[k].lc;
    if(r == y) rc = lst[k].rc;
    return lst[k].num;
    }
    pushdown(k, l, r);
    ll mid = l + r >> 1;
    if(y <= mid) return query(k << 1, l, mid, x, y);
    if(x > mid) return query(k << 1 | 1, mid + 1, r, x, y);
    ll res = query(k << 1, l, mid, x, y) + query(k << 1 | 1, mid + 1, r, x, y);
    if(lst[k << 1].rc == lst[k << 1 | 1].lc) --res;
    return res;
    }
    inline void uptree(ll x, ll y, ll z) {
    while(top[x] != top[y]) {
    if(dep[top[x]] < dep[top[y]]) std :: swap(x, y);
    modify(1, 1, n, id[top[x]], id[x], z);
    x = fa[top[x]];
    }
    if(id[x] > id[y]) std :: swap(x, y);
    modify(1, 1, n, id[x], id[y], z);
    }
    inline ll qy(ll x, ll y) {
    ll res = 0;
    pos1 = pos2 = 0;
    while(top[x] != top[y]) {
    if(dep[top[x]] < dep[top[y]]) std :: swap(x, y), std :: swap(pos1, pos2);
    res += query(1, 1, n, id[top[x]], id[x]);
    if(rc == pos1) --res;
    pos1 = lc, x = fa[top[x]];
    }
    if(id[x] > id[y]) std :: swap(x, y), std :: swap(pos1, pos2);
    res += query(1, 1, n, id[x], id[y]);
    if(lc == pos1) --res;
    if(rc == pos2) --res;
    return res;
    }
    int main() {
    n = sc(), m = sc();
    for(re int i = 1; i <= n; ++i)
    a[i] = sc();
    for(re int i = 1; i < n; ++i) {
    int x = sc(), y = sc();
    ADD(x, y), ADD(y, x);
    }
    cnt = 0;
    dfs1(1, 0), dfs2(1, 1), build(1, 1, n);
    while(m--) {
    char c[2];
    std :: cin >> c[0];
    int x = sc(), y = sc();
    if(c[0] == 'Q') {
    out(qy(x, y)), pc('\n');
    }
    else {
    int z = sc();
    uptree(x, y, z);
    }
    }
    return 0;
    }
    // Coded by dy.

rp++