zoukankan      html  css  js  c++  java
  • NOIP2013 D1T3 货车运输 zz耻辱记

    目录

    先来证明下lemma: 图上2点间最小边权最大的路径一定在MST上
    感性理解下:
    每次kruskal algo都连接最大的不成环边
    此时有2个未联通的联通块被连起来.
    那么考虑u, v两点的联通块 : 它们并起来时选的边最大. (将比这条边大的边加入生成树不能使得u,v联通)
    这个思想是kruskal重构树的基础(每个联通块选取一个代表点)

    sb题, 但是做的噎屎了, 花了1.5h
    我还是应该熟悉一下 最小生成树, 树上倍增和并查集
    2个sb错误:

    1. 见code l58
    2. 并查集没初始化

    code

    //file headers start
    #include<bits/stdc++.h>
    using namespace std;
    
    #define rep(i, _st, _ed) for(register int i = (_st); i <= (_ed); ++i)
    
    int read(){
        int f = 1, ans = 0; char c = getchar();
        while(!isdigit(c)) {
            if(c == '-') f = -1;
            c = getchar();
        }
        while(isdigit(c)) {
            ans = ans * 10 + c - '0';
            c = getchar();
        }
        return ans * f;
    }
    
    
    void put(int num) { printf("%d
    ", num); }
    void testread() { while(1) { int k = read(); put(k); if(!k) break;}}
    const int maxn = 10005, maxm = 50005;
    struct graph{
        int v, nxt, w;
    }edge[maxm*2];
    int head[maxn], n, m;
    void adde(int u, int v, int w){
        static int cnt = 0;
        edge[++cnt].v = v, edge[cnt].w = w;
        edge[cnt].nxt = head[u], head[u] = cnt;
    }
    //file headers end
    struct ee{
        int u, v, w;
        bool operator<(const ee &rhs)const{return w>rhs.w;}
    }e[maxm];
    int fa[maxn];
    int find(int u) {return (fa[u]==u)?u:fa[u] = find(fa[u]);}
    int dep[maxn], f[21][maxn], vis[maxn], d[21][maxn]; 
    void dfs(int u, int fa){
        dep[u] = dep[fa]+1, vis[u] = 1;
        f[0][u] = fa;
        for(int i = head[u]; i; i = edge[i].nxt){
            if(edge[i].v!=fa)dfs(edge[i].v, u), d[0][edge[i].v] = edge[i].w;
        }
    }
    int lcapth(int u, int v){
    	int ans = 1e9;
        if(dep[u] < dep[v]) swap(u, v);
        int i = 20;
        for(i = 20; i >= 0; i--)
        	if(dep[f[i][u]] >= dep[v])  ans = min(ans, d[i][u]), u = f[i][u];
        if(u == v) return ans;
        for(i = 20; i >= 0; i--){
            if(f[i][u] != f[i][v] ) { //omg 这里是f[i][u]不是dep[f[i][u]]
    	        ans = min(ans, d[i][u]), ans = min(ans, d[i][v]);
                u = f[i][u], v = f[i][v];           
            }
        }
        return min(ans, min(d[0][u], d[0][v]));
    }
    signed main(){
    //fileop("test");
        n = read(), m = read();
        rep(i, 1, m) {
            int u = read(), v = read(), w = read();
            e[i].u = u, e[i].v = v, e[i].w = w;
        }
        sort(e+1, e+m+1);
        rep(i, 1, n) fa[i] = i; //don't forget initialize bcj!!!
        rep(i, 1, m){
            if(find(e[i].v) != find(e[i].u)){
                adde(e[i].u, e[i].v, e[i].w), adde(e[i].v, e[i].u, e[i].w);
                fa[find(e[i].v)] = find(e[i].u);
                //printf("%d %d
    ", e[i].u, e[i].v);
            }
        }
        rep(i, 1, n) if(vis[i] == 0) dfs(i, 0), f[0][i] = i, d[0][i] = 1e9; //root should form self loop
        rep(i, 1, 20)rep(j, 1, n) f[i][j] = f[i-1][f[i-1][j]], d[i][j] = min(d[i-1][j], d[i-1][f[i-1][j] ]);
        int q = read();
        while(q--){
            int u = read(), v = read();
            if(find(u) == find(v)) put(lcapth(u, v)); 
            else put(-1);
        }
        return 0;
    }
    /*
    5 7
    4 3 4440
    3 1 22348
    1 3 28368
    2 4 25086
    5 3 6991
    4 3 10638
    3 1 11106
    4
    4 5
    1 3
    5 4
    2 5
    
    */
    
  • 相关阅读:
    poj 3068 Bridge Across Islands
    XidianOJ 1086 Flappy v8
    XidianOJ 1036 分配宝藏
    XidianOJ 1090 爬树的V8
    XidianOJ 1088 AK后的V8
    XidianOJ 1062 Black King Bar
    XidianOJ 1091 看Dota视频的V8
    XidianOJ 1098 突击数论前的xry111
    XidianOJ 1019 自然数的秘密
    XidianOJ 1109 Too Naive
  • 原文地址:https://www.cnblogs.com/Eroad/p/9807818.html
Copyright © 2011-2022 走看看