HDU 6005

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();
    }
}

  

 

posted @ 2018-03-12 06:36  RUSH_D_CAT  阅读(304)  评论(0编辑  收藏  举报