zoukankan      html  css  js  c++  java
  • 边双连通缩点+树dp 2015 ACM Arabella Collegiate Programming Contest的Gym

    http://codeforces.com/gym/100676/attachments

    题目大意:

    有n个城市,有m条路,每条路都有边长,如果某几个城市的路能组成一个环,那么在环中的这些城市就有传送门,能够瞬间抵达对方的城市(即距离为0),否则,就要走这条路,并且经过的路程为这条路的长度。

    问,找一个城市作为这些城市的首都

    要求:除了首都城市外,其他城市到首都的最大距离最短。

    思路:

    边双连通缩点以后就是一棵树,找树上的直径,首都一定是直径上的点。(orz,自己明明注意到了一定是直径上面的点,在之前的好多次的wa中却忘了是要找直径上的点了)

    //看看会不会爆int!数组会不会少了一维!
    //取物问题一定要小心先手胜利的条件
    #include <bits/stdc++.h>
    using namespace std;
    #pragma comment(linker,"/STACK:102400000,102400000")
    #define LL long long
    #define ALL(a) a.begin(), a.end()
    #define pb push_back
    #define mk make_pair
    #define fi first
    #define se second
    #define haha printf("haha
    ")
    /*
    思路:
    双连通缩点,然后随便找一个点树dp,
    树dp,距离最短的肯定就是直径上的某一个点
    */
    const int maxn = 1e5 + 5;
    const int maxm = 2e5 + 5;
    const LL inf = 1e17;
    vector<pair<int, LL> > G[maxn];
    int n, m;
    /*****************/
    int dfstime, bcccnt;
    bool iscut[maxn];
    int bccnu[maxn], pre[maxn];
    stack<int> s;
    vector<int> bcc[maxn];
    
    int dfs(int u, int fa){
        int lowu = pre[u] = ++dfstime;
        int len = G[u].size();
        int child = 0;
        s.push(u);
        for (int i = 0; i < len; i++){
            int v = G[u][i].fi;
            if (pre[v] == -1){
                child++;
                int lowv = dfs(v, u);
                lowu = min(lowv, lowu);
                if (lowv > pre[u]){
                    iscut[u] = true;
                }
            }
            else if (pre[v] < pre[u] && v != fa){
                lowu = min(lowu, pre[v]);
            }
        }
        if (lowu == pre[u]){
            bcccnt++;
            while (true){///边双连通分量是不存在重点的
                int v = s.top(); s.pop();
                bccnu[v] = bcccnt;
                bcc[bcccnt].pb(v);
                if (v == u) break;
            }
        }
        if (fa == -1 && child == 1) iscut[u] = false;
        return lowu;
    }
    
    void get_connect(){
        dfstime = bcccnt = 0;
        memset(iscut, false, sizeof(iscut));
        memset(bccnu, 0, sizeof(bccnu));
        memset(pre, -1, sizeof(pre));
        dfs(1, -1);
    }
    
    vector<pair<int, LL> > new_edge[maxn];
    void rebuild(){
        ///O(n + m)
        for (int i = 1; i <= bcccnt; i++){
            for (int j = 0; j < bcc[i].size(); j++){
                int u = bcc[i][j];
                for (int k = 0; k < G[u].size(); k++){
                    int v = G[u][k].fi;
                    LL val = G[u][k].se;
                    if (bccnu[u] != bccnu[v]){
                        new_edge[bccnu[u]].push_back(mk(bccnu[v], val));
                    }
                }
            }
        }
    /*    printf("bcccnt = %d
    ", bcccnt);
    
        cout << "new_edge.output" << endl;
        for (int i = 1; i <= bcccnt; i++){
            for (int j = 0; j < new_edge[i].size(); j++){
                printf("u = %d v = %d val = %d
    ", i, new_edge[i][j].fi, new_edge[i][j].se);
            }
            cout << endl;
        }
    */
    }
    
    int p; LL maxval;
    LL can[maxn];
    void dfs1(int u, int fa, LL sum){
        if (sum > maxval){
            maxval = sum, p = u;
        }
        for (int i = 0; i < new_edge[u].size(); i++){
            int v = new_edge[u][i].fi;
            LL tmp = new_edge[u][i].se;
            if (v == fa) continue;
            dfs1(v, u, sum + tmp);
        }
    }
    
    LL d1[maxn], d2[maxn];
    ///d1从最底下到目前节点的距离
    ///d2表示从根到目前节点的距离
    void dfs2(int u, int fa, LL sum){
        d2[u] = sum;
        for (int i = 0; i < new_edge[u].size(); i++){
            int v = new_edge[u][i].fi;
            LL val = new_edge[u][i].se;
            if (v == fa) continue;
            dfs2(v, u, sum + val);
            d1[u] = max(d1[u], d1[v] + val);
        }
    }
    
    LL mini;
    vector<int> ansp;
    void dfs3(int u, int fa){
        for (int i = 0; i < new_edge[u].size(); i++){
            int v = new_edge[u][i].fi;
            LL val = new_edge[u][i].se;
            if (v == fa) continue;
            if (d1[u] - val == d1[v]){
                dfs3(v, u);
                LL tmp = max(d1[u], d2[u]);
                if (mini > tmp){
                    ansp.clear(); mini = tmp; ansp.pb(u);
                }
                else if (mini == tmp){
                    ansp.pb(u);
                }
            }
        }
    }
    
    int main(){
        int t; cin >> t;
        while (t--){
            scanf("%d%d", &n, &m);
            for (int i = 1; i <= n; i++){
                G[i].clear(); bcc[i].clear();
                new_edge[i].clear();
            }
            for (int i = 1; i <= m; i++){
                int u, v; LL val; scanf("%d%d%lld", &u, &v, &val);
                G[u].pb(mk(v, val)); G[v].pb(mk(u, val));
            }
            get_connect();
            rebuild();
            p = 1, maxval = 0;
            dfs1(1, -1, 0);
    
            memset(d1, 0, sizeof(d1));
            memset(d2, 0, sizeof(d2));
            ansp.clear();
            dfs2(p, -1, 0LL);
    
            mini = inf;
            dfs3(p, -1);
    
            int ans = n + 1;
            for (int i = 0; i < ansp.size(); i++){
                int u = ansp[i];
                for (int j = 0; j < bcc[u].size(); j++){
                    ans = min(ans, bcc[u][j]);
                }
            }
            if (ans == n + 1) {ans = 1, mini = 0;}
            printf("%d %lld
    ", ans, mini);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    【常见问题汇总--持续更新】bootloader常见问题
    UCD9222 EN1/EN2
    cdce62005配置说明
    xilinx planahead partial reconfiguration
    诺基亚 920T
    不出现用户帐户控制-让Win7的用户账户控制(UAC)放过信任的程序
    python 拷贝文件夹下的文件 到 另一个文件夹
    python 计算两个日期间的小时数
    shell 解析 json
    shell 脚本运行 hive sql
  • 原文地址:https://www.cnblogs.com/heimao5027/p/6568084.html
Copyright © 2011-2022 走看看