• gym 101889I Imperial roads 最小生成树+LCA


    题目传送门

    题意:

          给出一幅无向带权图,q次询问,每次询问都求一棵包含给出的边的最小生成树。

    思路:

          首先求出最小生成树(kruskal),如果查询的边在最小生成树上,肯定是直接输出最小生成树,如果不在树上,那么这条必须连的边会和生成树形成一个环,我们就要去掉这个环上最大的一条边,就得到了答案(最小生成树是通过局部最优解得到全局最优解的,所以如果这样做,得到的是符合要求的最优解)。

         赛中队友提出一个问题,如果有两棵不同的最小生成树那这个做法不就错了吗,但其实如果有两棵最小生成树,这两棵树 相同权值的边的条数是一样的,是同分异构,所以做法还是正确的。

        而求环上的最大值,其实是求树上的最大值,所以在做kruskal的时候建立一幅新图,然后用lca求最大值。注意最大值的更新,很容易错。

    #include<cstdio>
    #include<algorithm>
    #include<iostream>
    #include<vector>
    #include<map>
    #include<set>
    #include<cstring>
    #include<queue>
    #include<stack>
    #include<cmath> 
    #define CLR(a,b) memset(a,b,sizeof(a))
    #define mkp(a,b) make_pair(a,b)
    using namespace std;
    const int maxn = 100010;
    typedef long long ll;
    int n, m, head[maxn], tot, vis[maxn],fa[maxn],deep[maxn],t,f[maxn][20],ma[maxn][20];
    int ans;
    struct edge {
        int to, w, Next;
        edge() {}
        edge(int to, int Next, int w) :to(to), Next(Next), w(w) {}
    }a[maxn * 4];
    map<pair<int, int >, int >mp;
    struct node {
        int u, v, w;
        node(int u, int v, int w) :u(u), v(v), w(w) {}
    };
    vector<node>g;
    void addv(int u, int v, int w) {
        a[++tot] = { v,head[u],w };
        head[u] = tot;
    }
    void init() {
        CLR(head, -1);
        for (int i = 1; i <= n; i++)fa[i] = i;
        tot = 0;
    }
    int find(int x)
    {
        return x == fa[x] ? x : fa[x] = find(fa[x]);
    }
    inline void baba(int x, int y)
    {
        int fx = find(x), fy = find(y);
        fa[fx] = fy;
    }
    bool cmp(node &a, node &b)
    {
        return a.w < b.w;
    }
    inline void kruskal() {
        sort(g.begin(), g.end(), cmp);
        for (int i = 0; i < m; i++)
        {
            int x = find(g[i].u);
            int y = find(g[i].v);
            if (x == y)continue;
            addv(g[i].u, g[i].v, g[i].w);
            addv(g[i].v, g[i].u, g[i].w);
            baba(x, y);
            ans += g[i].w;
        }
    }
    inline void bfs() {
        queue<int >q;
        q.push(1);
        deep[1] = 1;
        while (!q.empty())
        {
            int x = q.front();
            q.pop();
            for (int i = head[x]; i != -1; i = a[i].Next)
            {
                int y = a[i].to;
                if (deep[y])continue;
                deep[y] = deep[x] + 1;
                f[y][0] = x;
                ma[y][0] = a[i].w;
                for (int j = 1; j <= t; j++)
                {
                    f[y][j] = f[f[y][j - 1]][j - 1];
                    ma[y][j] = max(ma[y][j-1], ma[f[y][j - 1]][j - 1]);
                }
                q.push(y);
    
            }
        }
    }
    int lca(int x, int y)
    {
        int maxx = 0;
        if (deep[x] > deep[y])swap(x, y);
        for (int i = t; i >= 0; i--)
        {
            if (deep[f[y][i]] >= deep[x]) { 
                maxx = max(maxx, ma[y][i]);
                y = f[y][i]; 
            }
        }
        if (x == y)return maxx;
        for (int i = t; i >= 0; i--)
        {
            if (f[x][i] != f[y][i]) {
                maxx = max(maxx, ma[x][i]);
                maxx = max(maxx, ma[y][i]);
                x = f[x][i], y = f[y][i];
            }
        }
        //printf("debug
    ");
        maxx=max(maxx,ma[x][0]);
        maxx=max(maxx,ma[y][0]);
        return maxx;
    }
    int main() {
        scanf("%d%d", &n, &m);
        init();
        for(int i=1;i<=m;i++)
        {
            int u, v;
            int w;
            scanf("%d%d%d", &u, &v, &w);
            if (u > v)swap(u, v);
            mp[make_pair(u, v)] = w;
            g.push_back(node{ u,v,w });
        }
        kruskal();
        t = (int)(log(n) / log(2)) + 1;
        bfs();
    //    for (int i = 1; i <= n; i++)
    //    {
    //        printf("i:%d  deep:%d
    ", i, deep[i]);
    //    }
        int q;
        cin >> q;
        while (q--)
        {
            int u, v;
            scanf("%d%d", &u, &v);
            if (u > v)swap(u, v);
        //    printf("u:%d  v:%d
    ", u, v);
        //    printf("ans:%d   lca:%d  mp:%d
    ",ans,lca(u,v),mp[make_pair(u,v)]);
            printf("%d
    ", ans - lca(u, v)+mp[make_pair(u,v)]);
        }
    }
    
    /*
    
    5 7
    1 2 6
    1 3 4
    3 4 2
    1 5 7
    4 5 4
    2 4 1
    3 5 3
    1
    4 5
    
    
    */
  • 相关阅读:
    ACM题集以及各种总结大全
    ACM题集以及各种总结大全
    线段树题集
    线段树题集
    POJ 1159 Palindrome【LCS+滚动数组】【水题】
    POJ 1159 Palindrome【LCS+滚动数组】【水题】
    开课博客
    第一周学习进度
    开学测试
    寒假总结
  • 原文地址:https://www.cnblogs.com/mountaink/p/9583957.html
Copyright © 2020-2023  润新知