[bzoj] Network

http://www.lydsy.com/JudgeOnline/problem.php?id=3732

/*
    Kruskal 最小生成树
    树链剖分 最大值查询
    注意:可能会有几块不联通的图
*/

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <ctime>

using namespace std;
const int N = 25010;

#define gc getchar()
#define lson jd << 1
#define rson jd << 1 | 1 

int n, m, k, now = 1, tim, ans;
int bef[N], data[N], fat[N], head[N], tree[N], topp[N], fa[N], son[N], siz[N], deep[N];
struct Node_1{int u, v, w;} E[N << 1];
struct Node_2{int u, v, w, nxt;} G[N << 2];
struct Node_3{int l, r, Max;} T[N << 2];

bool cmp(Node_1 a, Node_1 b) {return a.w < b.w;}

struct Bzoj_3732{
    
    inline int read(){
        int x = 0; char c = gc;
        while(c < '0' || c > '9') c = gc;
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc;
        return x;
    }
    
    inline int getf(int x) {return fat[x] == x ? x : fat[x] = getf(fat[x]);}
    inline void add(int u, int v, int w) {G[now].v = v; G[now].w = w; G[now].nxt = head[u]; head[u] = now ++;}
    
    inline void Kruskal(){
        int js(0);
        for(int i = 1; i <= m; i ++){
            int u = E[i].u, v = E[i].v;
            int fu = getf(u), fv = getf(v);
            if(fu != fv) {
                js ++; fat[fu] = fv; 
                add(u, v, E[i].w); 
                add(v, u, E[i].w);
            }
            if(js == n - 1) return ;
        }
    }
    
    void dfs_find_son(int u, int f_, int dep){
        fa[u] = f_;
        deep[u] = dep;
        siz[u] = 1;
        for(int i = head[u]; ~ i; i = G[i].nxt){
            int v = G[i].v;
            if(v != f_){
                data[v] = G[i].w;
                dfs_find_son(v, u, dep + 1);
                siz[u] += siz[v];
                if(siz[v] > siz[son[u]]) son[u] = v;
            }
        }
    }
     
    void dfs_to_un(int u, int tp){
        topp[u] = tp;
        tree[u] = ++ tim;
        bef[tim] = u;
        if(!son[u]) return ;
        dfs_to_un(son[u], tp);
        for(int i = head[u]; ~ i; i = G[i].nxt){
            int v = G[i].v;
            if(v != fa[u] && v != son[u]) dfs_to_un(v, v);
        }
    }
    
    void build_tree(int l, int r, int jd){
        T[jd].l = l; T[jd].r = r;
        if(l == r) {T[jd].Max = data[bef[l]]; return ;}
        int mid = (l + r) >> 1;
        build_tree(l, mid, lson);
        build_tree(mid + 1, r, rson);
        T[jd].Max = max(T[lson].Max, T[rson].Max);
    }
    
    void Sec_A(int l, int r, int jd, int x, int y){
        if(x <= l && r <= y) {ans = max(ans, T[jd].Max); return ;}
        int mid = (l + r) >> 1;
        if(x <= mid) Sec_A(l, mid, lson, x, y);
        if(y > mid)  Sec_A(mid + 1, r, rson, x, y);
    }
    
    inline int Sec_A_imp(int x, int y){
        int tp1 = topp[x], tp2 = topp[y], ret = 0;
        while(tp1 != tp2){
            if(deep[tp1] < deep[tp2]) swap(x, y), swap(tp1, tp2);
            ans = 0;
            Sec_A(1, n, 1, tree[tp1], tree[x]);
            ret = max(ans, ret);
            x = fa[tp1];
            tp1 = topp[x];
        }
        if(x == y) return ret;
        if(deep[x] < deep[y]) swap(x, y);
        ans = 0;
        Sec_A(1, n, 1, tree[y] + 1, tree[x]);
        ret = max(ret, ans);
        return ret;
    }
}AC;

int main()
{
    n = AC.read(), m = AC.read(); k = AC.read();
    for(int i = 1; i <= n; i ++) fat[i] = i, head[i] = -1;
    for(int i = 1; i <= m; i ++)
        E[i].u = AC.read(), E[i].v = AC.read(), E[i].w = AC.read();
    sort(E + 1, E + m + 1, cmp);
    AC.Kruskal();
    for(int i = 1; i <= n; i ++) if(!deep[i]) AC.dfs_find_son(i, 0, 1);
    for(int i = 1; i <= n; i ++) if(!topp[i]) AC.dfs_to_un(i, i);
    AC.build_tree(1, n, 1);
    while(k --){
        int x = AC.read(), y = AC.read();
        int Answer = AC.Sec_A_imp(x, y);
        printf("%d\n", Answer);
    }
    
    return 0;
}

 与noip2013货车运输相似(一模一样)

货车运输:最大生成树 + 最小值查询

此题       :最小生成树 + 最大值查询

货车运输改几行代码就A了

#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <string>

using namespace std;
const int N = 15010;

#define oo 99999999

struct Node{
    int u, v, w;
}S[N << 1];
struct Edge{
    int u, v, w, nxt;
}E[N << 2];

int now = 1, n, m, js;
int head[N], p[N], f[N][30], g[N][30], deep[N];

inline int read(){
    int x = 0; char c = getchar();
    while(c < '0' || c > '9') c = getchar();
    while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
    return x; 
}

inline bool cmp(Node a, Node b){
    return a.w < b.w;
}

int getf(int x){
    return p[x] == x ? x : p[x] = getf(p[x]); 
}

void add(int u, int v, int w){
    E[now].v = v;
    E[now].w = w;
    E[now].nxt = head[u];
    head[u] = now ++;
}

inline void Kruskal(){
    for(int i = 1, doen = 1; i <= (m << 1) && doen < n; i ++){
        int u = S[i].u, v = S[i].v;
        int pu = getf(u), pv = getf(v);
        if(pu != pv){
            p[pu] = pv;
            add(u, v, S[i].w);
            add(v, u, S[i].w);
            doen ++;
        } 
    }
}

void make_deep(int u, int depth){
    deep[u] = depth;
    for(int i = head[u]; ~ i; i = E[i].nxt){
        int v = E[i].v;
        if(!deep[v]){
            f[v][0] = u;
            g[v][0] = E[i].w;
            make_deep(v, depth + 1);
        } 
    }
}

inline void make_jump(){
    for(int j = 1; (1 << j) <= n; j ++)
        for(int i = 1; i <= n; i ++)
            if(f[i][j - 1]) f[i][j] = f[f[i][j - 1]][j - 1], g[i][j] = max(g[i][j - 1], g[f[i][j - 1]][j - 1]);
}

inline int lca(int x, int y){
    int ret = -1;
    if(x == y) return 0;
    if(deep[x] < deep[y]) swap(x, y);
    int k = log2(deep[x]);
    for(int i = k; i >= 0; i --){
        if(deep[f[x][i]] >= deep[y]){
            ret = max(ret, g[x][i]);
            x = f[x][i];
        }
    }
    if(x == y) return ret;
    for(int i = k; i >= 0; i --){
        if(f[x][i] != f[y][i]){
            ret = max(ret, max(g[x][i], g[y][i]));
            x = f[x][i];
            y = f[y][i];
        }
    }
    ret = max(ret, max(g[x][0], g[y][0]));
    return ret;
}

int main()
{
    n = read();
    m = read();
    int T = read();
    for(int i = 1; i <= n; i ++) head[i] = -1, p[i] = i;
    for(int i = 1; i <= m; i ++) S[i].u = read(), S[i].v = read(), S[i].w = read();
    sort(S + 1, S + m + 1, cmp);
    Kruskal();
    for(int i = 1; i <= n; i ++) if(!deep[i]) make_deep(i, 1);//可能会有多块 
    make_jump();
    while(T --){
        int x = read(), y = read();
        int answer = lca(x, y);
        printf("%d\n", answer);
    }
    return 0; 
}

 

posted @ 2018-01-06 21:53  xayata  阅读(184)  评论(0编辑  收藏  举报