• 严格次小生成树(lca + 倍增)


    题目描述

    小C最近学了很多最小生成树的算法,Prim算法、Kurskal算法、消圈算法等等。正当小C洋洋得意之时,小P又来泼小C冷水了。小P说,让小C求出一个无向图的次小生成树,而且这个次小生成树还得是严格次小的,也就是说:如果最小生成树选择的边集是EM,严格次小生成树选择的边集是ES,那么需要满足:(value(e)表示边e的权值) eEMvalue(e)<eESvalue(e)

    这下小 C 蒙了,他找到了你,希望你帮他解决这个问题。

    输入输出格式

    输入格式:

    第一行包含两个整数N 和M,表示无向图的点数与边数。 接下来 M行,每行 3个数x y z 表示,点 x 和点y之间有一条边,边的权值为z。

    输出格式:

    包含一行,仅一个数,表示严格次小生成树的边权和。(数据保证必定存在严格次小生成树)


    首先用kruskal做一下最小生成树,把这些边称为“树边”,其余的为”非树边“,将每一条边权为v的非树边加到生成树中,则形成一个环,设环上的最大边和次大边分别为val1,val2,则显然:

    当 val1 < v 时 sum + v - val1 就是一个候选答案;

    当 val1 = v 时 sum + v - val2 就是一个候选答案;

    比较所有的候选答案,最小的即是该题的解。那么问题就转换成:如何求环上的最大边和次大边;

    可以用lca来写,f[i][k]表示点i向上跳2的k次方所对应的点,dis1[i][k] 和 dis2[i][k] 分别表示点i向上跳2的k次方所对应的最大边和次大边,则显然:

    f[i][k] = f[f[i][k - 1]][k - 1];
    dis1[i][k] = max(dis1[i][k - 1],dis1[f[i][k - 1]][k - 1]);
    if(dis1[i][k - 1] == dis1[f[i][k - 1]][k - 1])
      dis2[i][k] = max(dis2[i][k - 1],dis2[f[i][k - 1]][k - 1]);
    if(dis1[i][k - 1] > dis1[f[i][k - 1]][k - 1])
      dis2[i][k] = max(dis2[i][k - 1],dis1[f[i][k - 1]][k - 1]);
    if(dis1[i][k - 1] < dis1[f[i][k - 1]][k - 1])
      dis2[i][k] = max(dis1[i][k - 1],dis2[f[i][k - 1]][k - 1]);

    初值为:

    f[i][0] = father(i);
    dis1[i][0] = edge.v;
    dis2[i][0] = -INF(不存在)

    最后求一下,时间为(mlogn + mlogm);

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define ll long long
    #define INF 0x3f3f3f3f
    #define MAXN 1000010
    #define MAXM 100010
    
    inline int read() {
        int x = 0,ff = 1;
        char ch = getchar();
        while(!isdigit(ch)) {
            if(ch == '-') ff = -1;
            ch = getchar();
        }
        while(isdigit(ch)) {
            x = (x << 1) + (x << 3) + (ch ^ 48);
            ch = getchar();
        }
        return x * ff;
    }
    
    ll sum = 0;
    int n,m,tem = INF,tot = 0,cnt = 0;
    int vis[MAXN],fa[MAXN],lin[MAXN],deep[MAXN],f[MAXM][25],dis1[MAXM][25],dis2[MAXM][25];
    struct tree {
        int x,y,v;
    } t[MAXN];
    struct edge {
        int y,v,next;
    } e[MAXN];
    
    inline bool cmp(tree x,tree y) {
        return x.v < y.v;
    }
    
    inline int get(int x) {
        return fa[x] == x ? x : (fa[x] = get(fa[x]));
    }
    
    inline void add(int xx,int yy,int vv) {
        e[++tot].y = yy;
        e[tot].v = vv;
        e[tot].next = lin[xx];
        lin[xx] = tot;
    }
    
    void Kruskal() {
        sort(t + 1,t + m + 1,cmp);
        for(int i = 1; i <= n; ++i)
            fa[i] = i;
        for(int i = 1; i <= m && cnt < n - 1; ++i) {
            int x = get(t[i].x),y = get(t[i].y);
            if(x != y) {
                vis[i] = true;
                sum += t[i].v;
                fa[x] = y;
                cnt++;
                add(t[i].x,t[i].y,t[i].v);
                add(t[i].y,t[i].x,t[i].v);
            }
        }
    
    }
    
    void BFS() {
        queue < int > q;
        q.push(1);
        deep[1] = 1;
        while(!q.empty()) {
            int x = q.front();
            q.pop();
            for(int i = lin[x],y; i ; i = e[i].next) {
                if(deep[y = e[i].y]) continue;
                deep[y] = deep[x] + 1;
                f[y][0] = x;
                dis1[y][0] = e[i].v;
                dis2[y][0] = -INF;
                q.push(y);
                for(int j = 1; j <= 20; ++j) {
                    f[y][j] = f[f[y][j - 1]][j - 1];
                    dis1[y][j] = max(dis1[y][j - 1],dis1[f[y][j - 1]][j - 1]);
                    if(dis1[y][j - 1] == dis1[f[y][j - 1]][j - 1])
                        dis2[y][j] = max(dis2[y][j - 1],dis2[f[y][j - 1]][j - 1]);
                    if(dis1[y][j - 1] > dis1[f[y][j - 1]][j - 1])
                        dis2[y][j] = max(dis2[y][j - 1],dis1[f[y][j - 1]][j - 1]);
                    if(dis1[y][j - 1] < dis1[f[y][j - 1]][j - 1])
                        dis2[y][j] = max(dis1[y][j - 1],dis2[f[y][j - 1]][j - 1]);
                }
    
            }
        }
    }
    
    int lca(int x,int y) {
        if(deep[x] > deep[y]) swap(x,y);
        for(int i = 20; i >= 0; --i)
            if(deep[f[y][i]] >= deep[x])
                y = f[y][i];
        if(x == y)    return x;
        for(int i = 20; i >= 0; --i)
            if(f[x][i] != f[y][i])
                x = f[x][i],y = f[y][i];
        return f[x][0];
    }
    
    void cal(int x, int fa, int v) {
        int val1 = 0, val2 = 0;
        for(int i = 20; i >= 0; --i) {
            if(deep[f[x][i]] >= deep[fa]) {
                if (dis1[x][i] > val1) {
                    val2 = val1;
                    val1 = dis1[x][i];
                }
                val2  = max(val2, dis2[x][i]);
                x = f[x][i];
            }
        }
        if (val1 != v) tem = min(tem, v - val1);
        else tem = min(tem, v - val2);
    }
    
    int main() {
        n = read();
        m = read();
        for(int i = 1; i <= m; ++i) {
            t[i].x = read();
            t[i].y = read();
            t[i].v = read();
        }
        Kruskal();
        BFS();
        for(int i = 1; i <= m; ++i)
            if(!vis[i]) {
                int x = t[k].x,y = t[k].y;
                int fat = lca(x,y);
                cal(x,fat,v);
                cal(y,fat,v);
            }
        printf("%lld
    ",sum + tem);
        return 0;
    }

    .

  • 相关阅读:
    洛谷P3953 逛公园
    洛谷P1247 取火柴游戏
    洛谷P2024 食物链
    洛谷P2680 运输计划
    hdu 1495 非常可乐(bfs)
    poj3984 迷宫问题(简单的输出路径的bfs)
    Codeforces 729C Road to Cinema(二分)
    Codeforces Technocup 2017
    Codeforces Technocup 2017
    poj 2251 Dungeon Master(bfs)
  • 原文地址:https://www.cnblogs.com/AK-ls/p/10509986.html
Copyright © 2020-2023  润新知