樹鏈剖分+線段樹 HDOJ 4897 Little Devil I(小惡魔)

 

題目連接php

題意:c++

  給定一棵樹,每條邊有黑白兩種顏色,初始都是白色,如今有三種操做:ui

    1 u v:u到v路徑(最短)上的邊都取成相反的顏色3d

    2 u v:u到v路徑上相鄰的邊都取成相反的顏色(相鄰即僅有一個節點在路徑上)blog

    3 u v:查詢u到v路徑上有多少個黑色邊ip

思路:get

  對樹進行樹鏈剖分,分紅重鏈和輕鏈,用兩棵線段樹W,L來維護。W維護樹上在重鏈上的u和v之間的邊的翻轉狀況(操做在線段樹上的[pos[v],pos[u]]區間);L維護樹上在重鏈上的u和v之間的相鄰邊的翻轉狀況。那麼某一個點u與它父親節點fa[u]的邊的最終翻轉狀況爲:W(pos[u], pos[u])(若是邊是重鏈上的邊),W(pos[u], pos[u])^L(pos[fa[u]], pos[fa[u]])(若是邊是輕鏈)。對於1操做,只要簡單的在W上維護就能夠了。對於2操做,除了在L上操做,還要注意頭和尾的特殊處理(由於對於重鏈內的點,不包括頭尾,只在W上查詢),也就是u的重鏈上的兒子son[u]以及u的鏈頭p=belong[u]要在W上翻轉一次,結合圖可能更能理解。還有就是線段樹的操做了。it

 

另外:class

  u可能沒有son[u],默認爲虛點0,那麼在線段樹上須要加上一句話:if (l == r) return ;im

#include <bits/stdc++.h>

const int N = 1e5 + 5;

//線段樹
#define lson l, mid, o << 1
#define rson mid + 1, r, o << 1 | 1
struct Seg_Tree {
    int fp[N<<2], s[N<<2];
    void flip(int l, int r, int o) {
        s[o] = (r - l + 1) - s[o];
        fp[o] ^= 1;
    }
    void push_up(int o) {
        s[o] = s[o<<1] + s[o<<1|1];
    }
    void push_down(int l, int r, int o) {
        if (fp[o]) {
            int mid = l + r >> 1;
            flip (lson);
            flip (rson);
            fp[o] = 0;
        }
    }
    void build(int l, int r, int o) {
        fp[o] = s[o] = 0;
        if (l == r) {
            return ;
        }
        int mid = l + r >> 1;
        build (lson);
        build (rson);
    }
    void updata(int ql, int qr, int l, int r, int o) {
        if (ql <= l && r <= qr) {
            flip (l, r, o);
            return ;
        }
        if (l == r) return ;  //!
        push_down (l, r, o);
        int mid = l + r >> 1;
        if (ql <= mid) updata (ql, qr, lson);
        if (qr > mid) updata (ql, qr, rson);
        push_up (o);
    }
    int query(int ql, int qr, int l, int r, int o) {
        if (ql <= l && r <= qr) {
            return s[o];
        }
        push_down (l, r, o);
        int mid = l + r >> 1, ret = 0;
        if (ql <= mid) ret += query (ql, qr, lson);
        if (qr > mid) ret += query (ql, qr, rson);
        push_up (o);
        return ret;
    }
}W, L;

std::vector<int> edge[N];
int sz[N], dep[N], son[N], fa[N];
int pos[N], belong[N];
int loc;
int n;

int query(int u, int v) {
    int p = belong[u], q = belong[v], ret = 0;
    while (p != q) {
        if (dep[p] < dep[q]) {
            std::swap (p, q);
            std::swap (u, v);
        }
        if (u != p) {
            ret += W.query (pos[son[p]], pos[u], 1, n, 1);
        }
        ret += (W.query (pos[p], pos[p], 1, n, 1) ^ L.query (pos[fa[p]], pos[fa[p]], 1, n, 1));
        u = fa[p];
        p = belong[u];
    }
    
    if (u == v) return ret;
    
    if (dep[u] < dep[v]) {
        std::swap (u, v);
    }
    ret += W.query (pos[son[v]], pos[u], 1, n, 1);
    return ret;
}

void modify(int t, int u, int v) {
    int p = belong[u], q = belong[v];
    while (p != q) {
        if (dep[p] < dep[q]) {
            std::swap (p, q);
            std::swap (u, v);
        }
        if (t == 1) {
            W.updata (pos[p], pos[u], 1, n, 1);
        } else {
            L.updata (pos[p], pos[u], 1, n, 1);
            W.updata (pos[son[u]], pos[son[u]], 1, n, 1);
            W.updata (pos[p], pos[p], 1, n, 1);
        }
        u = fa[p];
        p = belong[u];
    }
    
    if (dep[u] < dep[v]) {
        std::swap (u, v);
    }
    if (t == 1) {
        if (u == v) return ;
        W.updata (pos[son[v]], pos[u], 1, n, 1);
    } else {
        L.updata (pos[v], pos[u], 1, n, 1);
        W.updata (pos[son[u]], pos[son[u]], 1, n, 1);
        W.updata (pos[v], pos[v], 1, n, 1);
    }
}

//樹鏈剖分
void DFS2(int u, int chain) {
    pos[u] = ++loc;
    belong[u] = chain;
    if (son[u]) {
        DFS2 (son[u], chain);
    }
    for (auto v: edge[u]) {
        if (v == fa[u] || v == son[u]) continue;
        DFS2 (v, v);
    }
}

void DFS1(int u, int pa) {
    sz[u] = 1; dep[u] = dep[pa] + 1;
    son[u] = 0; fa[u] = pa;
    for (auto v: edge[u]) {
        if (v == pa) continue;
        DFS1 (v, u);
        sz[u] += sz[v];
        if (sz[son[u]] < sz[v]) son[u] = v;
    }
}

void prepare() {
    sz[0] = dep[0] = fa[0] = 0;
    DFS1 (1, 0);
    loc = 0;
    DFS2 (1, 1);
    W.build (1, n, 1);
    L.build (1, n, 1);
}

void init_edge(int n) {
    for (int i=1; i<=n; ++i) {
        edge[i].clear ();
    }
}

int main() {
    int T;
    scanf ("%d", &T);
    while (T--) {
        scanf ("%d", &n);

        init_edge (n);
        for (int i=1; i<n; ++i) {
            int u, v;
            scanf ("%d%d", &u, &v);
            edge[u].push_back (v);
            edge[v].push_back (u);
        }
       
        prepare ();
        
        int q;
        scanf ("%d", &q);
        while (q--) {
            int t, u, v;
            scanf ("%d%d%d", &t, &u, &v);
            if (t == 3) {
                printf ("%d\n", query (u, v));
            } else {
                modify (t, u, v);
            }
        }
    }
    return 0;
}
相關文章
相關標籤/搜索