• 连通


    题目描述

    给出一张n个点,0条边的图,在第i个时刻(下标从1开始),向图中加入第i条无向边。

    有q次询问,每次询问u,v两个点最早在什么时刻连通。

    输入

    输出

    样例输入

    4 6
    1 3
    3 4
    1 4
    2 4
    2 3
    1 2
    4
    1 2
    3 4
    1 4
    2 3

    样例输出

    4
    2
    2
    4

    提示

    解题思路

    看到题目的第一感觉,发现数据是出奇地大,但这一道题目,肯定是可以构图的。(关键我连构图这一节都分析了好久才想到,而且还放弃并查集用了最短路)。事实上,此题就是需要并查集与LCA,图中的边很多,我们利用并查集其实也可以消去一些没有用的边,最后只可能有N-1条有效边,大大减小了时间复杂度。最后问连通没有,我们仅仅需要求出这一一段树上路径的最短路。

    我们处理并查集时,用秩优化,这里特别注意,不要用路径压缩,路径压缩可以说是把树全部打乱了,对我们来说这是致命的,我们用秩优化,因而树就是一棵长度为logn的树。

    但树其实是经过并查集处理,是很奇怪的,我们可以找到根节点,再进行dfs,真正构造出一棵树。求到深度,距离。

    构造完之后,就很水了,可以暴力求树上最大路径,还可以倍增,速度似乎要快一点。

    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<iostream>
    #include<vector>
    #include<queue>
    #include<cstdlib>
    #include<algorithm>
    using namespace std;
    struct edge{
        int u,v;
        edge(){};
        edge(int U,int V){
            u = U,v = V;
        }
    };
    int n,m,fa[50005],rank1[50005],q,mov[50005],dis[50005];
    vector <edge>G[50005];
      
    void makeset(int x){
        for (int i = 1;i <= x; i ++){
            fa[i] = i;
            rank1[i] = 1;
        }
    }
      
    int findset(int x){
        while (x != fa[x])
            x = fa[x];
        return x;
    }
      
    void unionset(int a,int b,int time){
        int t = findset(a);
        int t1 = findset(b);
        if (t == t1)
            return ;
        G[t].push_back(edge(t1,time));
        G[t1].push_back(edge(t,time));
        if (rank1[t] > rank1[t1])
            fa[t1] = t;
        else {
            fa[t] = t1;
            if (rank1[t] == rank1[t1])
                rank1[t1] ++;
        }
    }
      
    void dfs(int step){
        int x = G[step].size();
        for (int i = 0;i < x; i ++){
            if (!mov[G[step][i].u]){
                mov[G[step][i].u] = 1;
                rank1[G[step][i].u] = rank1[step] + 1;
                dis[G[step][i].u] = G[step][i].v;
                dfs(G[step][i].u);
            }
        }
    }
      
    int lca(int u,int v){
        int ans = 0;
        while (rank1[u] > rank1[v]){
            ans = max(dis[u],ans);
            u = fa[u];
        }
        while (rank1[v] > rank1[u]){
            ans = max(dis[v],ans);
            v = fa[v];
        }
        while (u != v){
            ans = max(dis[u],ans);
            u = fa[u];
            ans = max(dis[v],ans);
            v = fa[v];
        }
        return ans;
    }
      
    int main(){
        scanf ("%d%d",&n,&m);
        makeset(n);
        for (int i = 1 ;i <= m;i ++){
            int a,b;
            scanf ("%d%d",&a,&b);
            unionset(a,b,i);
        }
        for (int i = 1;i <= n;i ++){
            if (fa[i] == i){
                mov[i] = 1;
                rank1[i] = 1;
                dfs(i);
            }
        }
        scanf ("%d",&q);
        while (q --){
            int a,b;
            scanf ("%d%d",&a,&b);
            if (findset(a) != findset(b))
                printf("-1
    ");
            else if (a == b)
                printf("0
    ");
            else  
                printf("%d
    ",lca(a,b));
        }
    }

    总结

    我表示这道题考试时候是摸到了一点思路的,但确实是没想到树,构造这一棵树才是最为关键的。树构造出来,之后的答案就可以很好很轻松地做了。

  • 相关阅读:
    centos 安装docker
    vsphere client 创建虚拟机 如何关联到本地iso文件
    在centos7中使用supermin制作centos6.5docker镜像
    centos安装后,连接不上网络,yum命令执行can not find a valid baseurl for repo: base/7/x86-64
    佛祖保佑,永无BUG
    框架原理
    android 中解析XML的方法(转)
    android 项目随记一
    android事件系列-onTouch事件与手势操作
    深入理解 AngularJS 的 Scope(转)
  • 原文地址:https://www.cnblogs.com/lover-fucker/p/13566688.html
Copyright © 2020-2023  润新知