101669L Divide and Conquer 樹的啟發式合併
阿新 • • 發佈:2018-12-15
題意:
給你一個圖,這個圖由兩個樹構成,問全域性最小割和方案數。
題解:
至少一個點度數不超過3,所以答案不超過3。
所以一定有一個樹只割了一條邊,列舉割的邊,看子樹和非子樹點在第二顆樹有多少個連邊就行了。用啟發式合併。
程式碼:
#include <bits/stdc++.h> #ifdef LOCAL #define debug(x) cout<<#x<<" = "<<(x)<<endl; #else #define debug(x) 1; #endif #define chmax(x,y) x=max(x,y) #define chmin(x,y) x=min(x,y) #define lson id<<1,l,mid #define rson id<<1|1,mid+1,r #define lowbit(x) x&-x #define mp make_pair #define pb push_back #define fir first #define sec second using namespace std; typedef long long ll; typedef unsigned long long ull; typedef pair<int, int> pii; const int MOD = 1e9 + 7; const double PI = acos (-1.); const double eps = 1e-10; const int INF = 0x3f3f3f3f; const ll INFLL = 0x3f3f3f3f3f3f3f3f; const int MAXN = 1e5 + 5; struct Tree { vector<int> G[MAXN]; int son[MAXN], siz[MAXN], n; void add (int x, int y) { G[x].pb (y); } void dfs (int now, int par) { siz[now] = 1; for (int i : G[now]) { if (i == par) continue; dfs(i, now); if (siz[son[now]] <= siz[i]) son[now] = i; siz[now] += siz[i]; } } } tr[2]; int vis[MAXN]; int out; void cal (int now, Tree & b) { vis[now] ^= 1; for (int i : b.G[now]) { if (vis[i] != vis[now]) out++; else out--; } } void edt (int now, int par, Tree & a, Tree &b) { cal(now, b); for (int i : a.G[now]) if (i != par) edt(i, now, a, b); } pii ret; void dfs (int now, int par, int kep, Tree &a, Tree & b) { for (int i : a.G[now]) { if (i == par || i == a.son[now]) continue; dfs(i, now, 0, a, b); } if (a.son[now]) dfs(a.son[now], now, 1, a, b); cal(now, b); for (int i : a.G[now]) if (i != par && i != a.son[now]) edt(i, now, a, b); if (par) { if (out < ret.first) ret.first = out, ret.second = 1; else if (out == ret.first) ret.second++; } if (!kep) edt(now, par, a, b); } void solve (Tree &a, Tree & b) { ret = {INF, 0}; out = 0; a.dfs(1, 0); b.dfs(1, 0); dfs(1, 0, 0, a, b); if (ret.first == 1) { printf ("2 %d\n", ret.second); } else { out = 0; dfs(1, 0, 0, b, a); printf ("3 %d\n", ret.second); } } int main() { #ifdef LOCAL freopen ("input.txt", "r", stdin); #endif int n; scanf ("%d", &n); for (int i = 1; i < n; i++) { int x, y; scanf ("%d %d", &x, &y); tr[0].add(x, y); tr[0].add(y, x); } for (int i = 1; i < n; i++) { int x, y; scanf ("%d %d", &x, &y); tr[1].add(x, y); tr[1].add(y, x); } solve(tr[0], tr[1]); return 0; }