圓方樹簡介(UOJ30:CF Round #278 Tourists)

我寫這篇博客的緣由

證實我也是學過圓方樹的
順便存存代碼c++


前置技能

雙聯通份量:點雙
而後就沒辣spa

圓方樹

創建

新建一個圖
定義原圖中的全部點爲圓點
對於每一個點雙聯通份量(只有兩個點的也算)
創建一個方點,向全部的點雙內的點連邊
code

性質

  1. 必定是個森林
  2. 每一個點雙有惟一的方點
  3. 圓點方點相間分佈,相同點不相鄰

等等blog

例子 1

題面

求能夠出如今兩點之間的簡單路路徑上的點的最大權值,不帶修改get

分析

考慮用圓方樹來解決
設圓點權值爲自己,方點權值爲點雙中的最大權值
那麼就是樹上的路徑最大權值博客

例子 2

仍是上面的題,能夠修改一個點的權值
相似題UOJ
用老方法
每次修改時更改圓點鏈接的全部方點
沒了?
不存在的,這樣每次修改是\(O(n)\)的,容易被卡
換一種定義:方點權值不包括它的父親圓點
那麼每次修改就只要修改圓點的父親
注意若是\(lca\)是方點,還要算上它父親方點的權值
堆+線段樹(zkw辣)+樹剖+圓方樹+tarjanit

UOJ代碼io

# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
const int _(4e5 + 5);

IL int Input(){
    RG int x = 0, z = 1; RG char c = getchar();
    for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
    for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
    return x * z;
}

struct Edge{
    int next[_], first[_], to[_], cnt;

    IL void Init(){
        Fill(first, -1);
    }

    IL void Add(RG int u, RG int v){
        next[cnt] = first[u], to[cnt] = v, first[u] = cnt++;
    }
} G1, G2;
struct Segment{
    int mn[_ << 2], M;

    IL void Init(RG int n){
        Fill(mn, 127);
        for(M = 1; M < n; M <<= 1);
    }

    IL void Update(RG int x, RG int y){
        x += M - 1, mn[x] = y;
        for(x >>= 1; x; x >>= 1) mn[x] = min(mn[x << 1], mn[x << 1 | 1]);
    }

    IL int Query(RG int l, RG int r){
        RG int ret = 2e9;
        for(l += M - 2, r += M; l ^ r ^ 1; l >>= 1, r >>= 1){
            if(~l & 1) ret = min(ret, mn[l ^ 1]);
            if(r & 1) ret = min(ret, mn[r ^ 1]);
        }
        return ret;
    }
} T;
struct Heap{
    priority_queue <int> Q1, Q2;

    IL void Push(RG int x){
        Q1.push(-x);
    }

    IL void Del(RG int x){
        Q2.push(-x);
    }

    IL int Top(){
        while(!Q2.empty() && Q1.top() == Q2.top()) Q1.pop(), Q2.pop();
        return -Q1.top();
    }
} Q[_];
int tmp, n, m, q, val[_], dfn[_], low[_], Index, S[_];
int size[_], top[_], fa[_], deep[_], son[_];

IL void Tarjan(RG int u){
    dfn[u] = low[u] = ++Index, S[++S[0]] = u;
    for(RG int e = G1.first[u]; e != -1; e = G1.next[e]){
        RG int v = G1.to[e], x;
        if(!dfn[v]){
            Tarjan(v), low[u] = min(low[u], low[v]);
            if(low[v] >= dfn[u]){
                val[++n] = 2e9, x = 0;
                do{
                    x = S[S[0]--];
                    G2.Add(n, x), G2.Add(x, n);
                } while(x != v);
                G2.Add(n, u), G2.Add(u, n);
            }
        }
        else low[u] = min(low[u], dfn[v]);
    }
}

IL void Dfs1(RG int u){
    size[u] = 1;
    if(u <= tmp && fa[u]) Q[fa[u]].Push(val[u]);
    for(RG int e = G2.first[u]; e != -1; e = G2.next[e]){
        RG int v = G2.to[e];
        if(size[v]) continue;
        fa[v] = u, deep[v] = deep[u] + 1;
        Dfs1(v);
        size[u] += size[v];
        if(size[v] > size[son[u]]) son[u] = v;
    }
}

IL void Dfs2(RG int u, RG int Top){
    dfn[u] = ++Index, top[u] = Top;
    if(son[u]) Dfs2(son[u], Top);
    for(RG int e = G2.first[u]; e != -1; e = G2.next[e])
        if(!dfn[G2.to[e]]) Dfs2(G2.to[e], G2.to[e]);
}

IL int Query(RG int u, RG int v){
    RG int ret = 2e9;
    while(top[u] ^ top[v]){
        if(deep[top[u]] > deep[top[v]]) swap(u, v);
        ret = min(ret, T.Query(dfn[top[v]], dfn[v]));
        v = fa[top[v]];
    }
    if(dfn[u] > dfn[v]) swap(u, v);
    ret = min(ret, T.Query(dfn[u], dfn[v]));
    if(u > tmp) ret = min(ret, val[fa[u]]);
    return ret;
}

int main(RG int argc, RG char* argv[]){
    G1.Init(), G2.Init();
    tmp = n = Input(), m = Input(), q = Input();
    for(RG int i = 1; i <= n; ++i) val[i] = Input();
    for(RG int i = 1; i <= m; ++i){
        RG int u = Input(), v = Input();
        G1.Add(u, v), G1.Add(v, u);
    }
    for(RG int i = 1; i <= tmp; ++i) if(!dfn[i]) Tarjan(i);
    Fill(dfn, 0), Index = 0, T.Init(n);
    Dfs1(1), Dfs2(1, 1);
    for(RG int i = 1; i <= n; ++i) T.Update(dfn[i], val[i]);
    for(RG int i = tmp + 1; i <= n; ++i) T.Update(dfn[i], Q[i].Top());
    for(RG int i = 1, a, b; i <= q; ++i){
        RG char op; scanf(" %c", &op);
        a = Input(), b = Input();
        if(op == 'C'){
            if(fa[a]) Q[fa[a]].Del(val[a]);
            val[a] = b, T.Update(dfn[a], val[a]);
            if(fa[a]) Q[fa[a]].Push(val[a]);
            if(fa[a]) T.Update(dfn[fa[a]], Q[fa[a]].Top());
        }
        else printf("%d\n", Query(a, b));
    }
    return 0;
}
相關文章
相關標籤/搜索