[SDOI2011]染色

题意

Here

思考

树上链修改,树上链查询,考虑树链剖分

染色操作:线段树区间修改,注意 \(lazy\) 数组的赋初值

查询操作,线段树每个节点记录该段左端点颜色和右端点颜色,树上跳 \(top\) 的时候注意合并的处理,(如果现在端的右端点颜色等于上一段左端点颜色,就少计一种颜色),主要是细节问题,感觉还是很锻炼码力的

代码

#include<bits/stdc++.h>
#define ls(pos) pos << 1
#define rs(pos) pos << 1 | 1
using namespace std;
int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x * f;
}
const int M = 300030;
const int N = 300030;
struct node{
    int nxt, to;
}edge[M << 1];
int head[N], num;
void build(int from, int to){
    edge[++num].nxt = head[from];
    edge[num].to = to;
    head[from] = num;
}
namespace Seg{
    struct node2{
        int sum, cl, cr;
    };
    int d[N], fa[N], sz[N], son[N], top[N], seg[N], rev[N], val[N], cnt;
    void dfs(int u, int f){
        d[u] = d[f] + 1; sz[u] = 1; fa[u] = f;
        for(int i=head[u]; i; i=edge[i].nxt){
            int v = edge[i].to;
            if(v == f) continue;
            dfs(v, u);
            sz[u] += sz[v];
            if(sz[son[u]] < sz[v]) son[u] = v;
        }
    }
    void dfs2(int u, int topf){
        top[u] = topf; seg[u] = ++ cnt; rev[cnt] = u;
        if(!son[u]) return;
        dfs2(son[u], topf);
        for(int i=head[u]; i; i=edge[i].nxt){
            int v = edge[i].to;
            if(!seg[v]) dfs2(v, v);
        }
    }
    int S[N << 2], l[N << 2], r[N << 2], C[N << 2];
    void pushup(int pos){
        l[pos] = l[ls(pos)]; r[pos] = r[rs(pos)];
        if(r[ls(pos)] == l[rs(pos)]){
            S[pos] = S[ls(pos)] + S[rs(pos)] - 1;
        }
        else S[pos] = S[ls(pos)] + S[rs(pos)];
    }
    void builds(int pos, int ll, int rr){
        C[pos] = -1;
        if(ll == rr) {
            S[pos] = 1; l[pos] = r[pos] = val[rev[ll]];
            return;
        }
        int mid = (ll + rr) >> 1;
        builds(ls(pos), ll, mid);
        builds(rs(pos), mid+1, rr);
        pushup(pos);
    }
    void change(int pos, int v){
        S[pos] = 1; C[pos] = v; l[pos] = r[pos] = v;
    }
    void pushdown(int pos){
        if(C[pos] != -1){
            change(ls(pos), C[pos]);
            change(rs(pos), C[pos]);
            C[pos] = -1;
        }
    }
    void modify(int pos, int l, int r, int x, int y, int v){
        if(l > y || r < x) return;
        if(x <= l && r <= y) return change(pos, v);
        pushdown(pos);
        int mid = (l + r) >> 1;
        if(x <= mid) modify(ls(pos), l, mid, x, y, v);
        if(y > mid) modify(rs(pos), mid+1, r, x, y, v);
        pushup(pos);
    }
    node2 query(int pos, int ll, int rr, int x, int y){
        if(x <= ll && rr <= y) {
            node2 ans = (node2){S[pos], l[pos], r[pos]};
            return ans;
        }
        pushdown(pos);
        int mid = (ll + rr) >> 1;
        if(y <= mid) return query(ls(pos), ll, mid, x, y);
        else if(x > mid) return query(rs(pos), mid+1, rr, x, y);
        else{
            node2 L = query(ls(pos), ll, mid, x, y);
            node2 R = query(rs(pos), mid+1, rr, x, y);
            node2 ans;
            ans.cl = L.cl; ans.cr = R.cr;
            if(R.cl == L.cr){
                ans.sum = L.sum + R.sum - 1;
            }
            else ans.sum = L.sum + R.sum;
            return ans;
        }
    }
    void Tmodify(int u, int v, int w){
        while(top[u] != top[v]){
            if(d[top[u]] < d[top[v]]) swap(u, v);
            modify(1, 1, cnt, seg[top[u]], seg[u], w);
            u = fa[top[u]];
        }
        if(d[u] > d[v]) swap(u, v);
        modify(1, 1, cnt, seg[u], seg[v], w);
    }
    int Tquery(int u, int v){
        int lal = -1, lar = -1, ans = 0;
        while(top[u] != top[v]){
            if(d[top[u]] < d[top[v]]) swap(u, v), swap(lal, lar);
            node2 ans1 = query(1, 1, cnt, seg[top[u]], seg[u]);
            ans += ans1.sum;
            if(lal == ans1.cr) ans --; lal = ans1.cl;
            u = fa[top[u]];
        }
        if(d[u] > d[v]) swap(u, v), swap(lal, lar);
        node2 ans1 = query(1, 1, cnt, seg[u], seg[v]);
        ans += ans1.sum;
        if(lal == ans1.cl) ans --;
        if(lar == ans1.cr) ans --;
        return ans;
    }
}
using namespace Seg;
int n, m;
int main(){
    n = read(); m = read();
    for(int i=1; i<=n; i++) val[i] = read();
    for(int i=1; i<=n-1; i++){
        int u = read(), v = read();
        build(u, v); build(v, u);
    }
    dfs(1, 0); dfs2(1, 1); builds(1, 1, cnt);
    while(m --){
        char op[10]; scanf("%s", op + 1);
        if(op[1] == 'C'){
            int a = read(), b = read(), c = read();
            Tmodify(a, b, c);
        }
        else{
            int a = read(), b = read();
            printf("%d\n", Tquery(a, b));
        }
    }
    return 0;
}

总结

比较码农的题,注意细节就 \(ok\) ~

posted @ 2018-11-05 21:55  alecli  阅读(70)  评论(0编辑  收藏  举报