bzoj 2238

最小生成树 + 链剖
建立最小生成树
将所有不在最小生成树上的边的两点之间的边上加入该边的权值
每条边在加入权值时取最小
对于不在最小生成树上的边删去后最小生成树不变
对于在最小生成树上的边删去后的最小增量(相对于MST - 该边的权值)为两点之间路径的最小值

#include <bits/stdc++.h>

const int N = 5e4 + 10, M = N << 1;

int head[N], cnt = 1;
struct Node_1 {int u, v, w, num; bool be_use;} E[M];
struct Node {int u, v, nxt;} G[N << 1];
int fa[N], tree[N], deep[N], size[N], son[N], topp[N], bel[M];
int n, m, T, tim;
int Mst, father[N], Use_js;
int Minn[N << 2];

bool Cmp_1(Node_1 a, Node_1 b) {return a.num < b.num;}
bool Cmp(Node_1 a, Node_1 b) {return a.w < b.w;}
int Get_fa(int x) {return father[x] == x ? x : father[x] = Get_fa(father[x]);}
void Add(int u, int v) {G[cnt].v = v; G[cnt].nxt = head[u]; head[u] = cnt ++;}

void Make_mst() {
    std:: sort(E + 1, E + m + 1, Cmp);
    for(int i = 1; i <= n; i ++) father[i] = i;
    for(int i = 1; i <= m; i ++) {
        int u = E[i].u, v = E[i].v, fa_u = Get_fa(u), fa_v = Get_fa(v);
        if(fa_u != fa_v) {
            E[i].be_use = 1;
            Use_js ++;
            father[fa_u] = fa_v;
            Mst += E[i].w;
            Add(E[i].u, E[i].v), Add(E[i].v, E[i].u);
        }
        if(Use_js == n - 1) return ;
    }
}

void Dfs_1(int u, int f_, int dep) {
    fa[u] = f_;
    deep[u] = dep;
    size[u] = 1;
    for(int i = head[u]; ~ i; i = G[i].nxt) {
        int v = G[i].v;
        if(v != f_) {
            Dfs_1(v, u, dep + 1);
            size[u] += size[v];
            if(size[v] > size[son[u]]) son[u] = v;
        }
    }
}

void Dfs_2(int u, int tp) {
    tree[u] = ++ tim;
    topp[u] = tp;
    if(!son[u]) return ;
    Dfs_2(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_2(v, v); 
    }
}

#define lson jd << 1
#define rson jd << 1 | 1

void Sec_G(int l, int r, int jd, int x, int y, int z) {
    if(x <= l && r <= y) {
        Minn[jd] = std:: min(Minn[jd], z);
        return ;
    }
    int mid = (l + r) >> 1;
    if(x <= mid) Sec_G(l, mid, lson, x, y, z);
    if(y > mid)  Sec_G(mid + 1, r, rson, x, y, z);
}

void Sec_G_Imp(int x, int y, int w) {
    int tpx = topp[x], tpy = topp[y];
    while(tpx != tpy) {
        if(deep[tpx] < deep[tpy]) std:: swap(x, y), std:: swap(tpx, tpy);
        Sec_G(1, n, 1, tree[tpx], tree[x], w);
        x = fa[tpx];
        tpx = topp[x];
    }
    if(x == y) return ;
    if(deep[x] < deep[y]) std:: swap(x, y);
    Sec_G(1, n, 1, tree[y] + 1, tree[x], w);
}

int Answer;

void Poi_A(int l, int r, int jd, int x) {
    if(l == r) {Answer = Minn[jd]; return ;}
    Minn[lson] = std:: min(Minn[lson], Minn[jd]);
    Minn[rson] = std:: min(Minn[rson], Minn[jd]);
    int mid = (l + r) >> 1;
    if(x <= mid) Poi_A(l, mid, lson, x);
    else Poi_A(mid + 1, r, rson, x);
} 

#define gc getchar()

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

int main() {
    n = read(), m = read();
    for(int i = 1; i <= n; i ++) head[i] = -1;
    for(int i = 1; i <= m; i ++) {
        E[i].u = read(), E[i].v = read(), E[i].w = read();
        E[i].num = i;
    } 
    T = read();
    Make_mst();
    if(Use_js != n - 1) {for(; T; T --) puts("Not connected"); return 0;}
    Dfs_1(1, 0, 1);
    Dfs_2(1, 1);
    for(int i = 1; i <= (N << 2); i ++) Minn[i] = 999999999;
    std:: sort(E + 1, E + m + 1, Cmp_1);
    for(int i = 1; i <= m; i ++) bel[i] = (deep[E[i].u] > deep[E[i].v] ? E[i].u : E[i].v);
    for(int i = 1; i <= m; i ++) 
        if(!E[i].be_use) 
            Sec_G_Imp(E[i].u, E[i].v, E[i].w);
    for(; T; T --) {
        int x = read();
        if(!E[x].be_use) {
            printf("%d\n", Mst);
            continue ;
        }
        Answer = 999999999;
        Poi_A(1, n, 1, tree[bel[x]]);
        if(Answer == 999999999) puts("Not connected");
        else printf("%d\n", Mst - E[x].w + Answer);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/zjoiak/p/9254834.html