pair套pair套pair套pair!多么优(S)雅(B)的代码!
题解:
最小环,有且仅有一条边不在最小生成树上。
注意到一个性质:在最小生成树上ADD一条非树边,我们会得到一个环,那么这条非树边肯定是环上权值最大的。
然后就可以反证了。
【UPD2018/10/9:反证个锤子啊,这个做法整个就错了啊。最小环可以有超过一条边不在生成树上的,数据水了啊】
#include <iostream>
#include <cstring>
#include <vector>
#include <map>
#include <algorithm>
using namespace std;
#define mp make_pair
const int INF = 1000000007;
typedef pair<int, int> pii;
const int N = 8002;
int t, n, cas;
int x[N], y[N], c[N], d[N], w[N], used[N];
map<pii, int> id; int cnt;
int par[N];
vector< pair< pair<int, pii>, int> > edge;
vector<pii> g[N]; int vis[N];
// Tree
int fa[N][20], dep[N], sum[N][20];
int find(int x) {
return par[x] = (par[x] == x) ? x : par[x] = find(par[x]);
}
void dfs(int u, int p) {
vis[u] = 1;
for (int i = 0; i < g[u].size(); i ++) {
int v = g[u][i].first;
if (v == p) continue;
dep[v] = dep[u] + 1;
fa[v][0] = u;
sum[v][0] = g[u][i].second;
dfs(v, u);
}
}
void init_LCA() {
for (int i = 1; i <= cnt; i ++) if (! vis[i]) {
dep[i] = 1, fa[i][0] = 1; sum[i][0] = 0;
dfs(i, -1);
}
for (int i = 1; i < 20; i ++) {
for (int j = 1; j <= cnt; j ++) {
sum[j][i] = sum[j][i-1] + sum[fa[j][i-1]][i-1];
fa[j][i] = fa[fa[j][i-1]][i-1];
}
}
}
int query(int u, int v) {
int ret = 0;
if (dep[u] < dep[v]) swap(u, v);
int dt = dep[u] - dep[v];
for (int i = 0; i < 20; i ++) {
if ( (dt >> i) & 1 )
ret += sum[u][i], u = fa[u][i];
}
if (u == v) return ret;
for (int i = 19; i >= 0; i --) {
if (fa[u][i] != fa[v][i])
ret += sum[u][i] + sum[v][i], u = fa[u][i], v = fa[v][i];
}
ret += sum[u][0] + sum[v][0];
return ret;
}
void init() {
for (int i = 0; i < N; i ++) {
par[i] = i, used[i] = 0, vis[i] = 0;
g[i].clear();
}
edge.clear();
id.clear(); cnt = 0;
scanf("%d", &n);
for (int i = 1; i <= n; i ++) {
scanf("%d %d %d %d %d", &x[i], &y[i], &c[i], &d[i], &w[i]);
if (! id[mp(x[i], y[i])]) id[mp(x[i], y[i])] = ++ cnt;
if (! id[mp(c[i], d[i])]) id[mp(c[i], d[i])] = ++ cnt;
edge.push_back(mp(mp(w[i], mp(id[mp(x[i], y[i])], id[mp(c[i], d[i])])), i));
}
sort(edge.begin(), edge.end());
for (int i = 0; i < edge.size(); i ++) {
int u = edge[i].first.second.first;
int v = edge[i].first.second.second;
int pu = find(u), pv = find(v);
if (pu != pv) {
used[edge[i].second] = 1;
g[u].push_back( make_pair(v, edge[i].first.first) );
g[v].push_back( make_pair(u, edge[i].first.first) );
par[pu] = pv;
}
}
init_LCA();
}
void ok() {
int ret = INF;
for (int i = 1; i <= n; i ++) {
if (used[i] == 0) {
ret = min(ret, query(id[mp(x[i],y[i])], id[mp(c[i],d[i])]) + w[i]);
}
}
printf("Case #%d: %d\n", ++cas, ret > 500000000 ? 0 : ret);
}
int main() {
scanf("%d", &t);
while (t --) {
init();
ok();
}
}