AGC014E Blue and Red Tree [啓發式合併]

Description:
一棵樹的邊全部是藍色的,每次可以選擇一條全是藍色邊的鏈,刪除其中一條邊並用紅邊連接鏈的端點。問是否可以變成另一棵樹。


Solution:
倒着考慮這個過程,發現每次相當於連接兩個同時在兩棵樹都有邊的兩個點,然後縮成一個連通塊。那麼用並查集維護連通塊,set 維護相鄰的點,啓發式合併就行了。


#include <bits/stdc++.h> 
using namespace std;
const int maxn = 1e5 + 5;
int n;
int fa[maxn];
set<int> G[maxn], g[maxn];
queue<pair<int, int> > q;
int find(int x) {
    return x == fa[x] ? x : fa[x] = find(fa[x]);
}
pair<int, int> mp(int x, int y) {
    if(x > y) {
        swap(x, y);
    }
    return make_pair(x, y);
}
int main() {
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i) {
        fa[i] = i;
    }
    for(int i = 1; i < n; ++i) {
        int u, v;
        scanf("%d%d", &u, &v);
        G[u].insert(v);
        G[v].insert(u);
    }
    for(int i = 1; i < n; ++i) {
        int u, v;
        scanf("%d%d", &u, &v);
        g[u].insert(v);
        g[v].insert(u);
        if(G[u].find(v) != G[u].end()) {
            q.push(mp(u, v));
        }
    }
    for(int i = 1, u, v; i < n; ++i) {
        do {
            if(q.empty()) {
                return puts("NO"), 0;
            }
            u = find(q.front().first);
            v = find(q.front().second);
            q.pop();
        } while(u == v);
        if(g[u].size() > g[v].size()) {
            swap(u, v);
        }
        g[u].erase(v);
        g[v].erase(u);
        G[u].erase(v);
        G[v].erase(u);
        fa[u] = v;
        set<int> :: iterator it;
        for(it = G[u].begin(); it != G[u].end(); ++it) {
            if(g[*it].find(v) != g[*it].end()) {
                q.push(mp(*it, v));
            }
        }
        for(it = g[u].begin(); it != g[u].end(); ++it) {
            if(G[*it].find(v) != G[*it].end()) {
                q.push(mp(*it, v));
            }
        }
        for(it = G[u].begin(); it != G[u].end(); ++it) {
            G[*it].erase(u);
            G[*it].insert(v);
            G[v].insert(*it);
        }
        for(it = g[u].begin(); it != g[u].end(); ++it) {
            g[*it].erase(u);
            g[*it].insert(v);
            g[v].insert(*it);
        }
    }
    return puts("YES"), 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章