• 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
    ", ++cas, ret > 500000000 ? 0 : ret);
    }
    
    int main() {
        scanf("%d", &t);
        while (t --) {
            init();
            ok();
        }
    }
    

      

  • 相关阅读:
    Visual Studio Code 配置C/C++环境
    二叉链的基本操作
    回文自动机
    吊打线段树的超级树状数组
    Treap平衡树
    uni-app nvue页面动态修改导航栏按钮
    uni-app map组件关于marker标记点动态设置的问题
    uni-app 提示 v-for 暂不支持循环数据
    uni-app APP端隐藏导航栏自定义按钮
    uni-app路径规划(打开第三方地图实现)
  • 原文地址:https://www.cnblogs.com/RUSH-D-CAT/p/8547315.html
Copyright © 2020-2023  润新知