• codeforces#1166F. Vicky's Delivery (Service并查集+启发式合并)


    题目链接:

    https://codeforces.com/contest/1166/problem/F

    题意:

    给出节点数为$n$,边数为$m$的图,保证每个点对都是互连的

    定义彩虹路:这条路经过$k$个节点,对于$x(x\%2=0)$节点,的左右两条边颜色相同

    现在有$q$次操作

    第一种操作是添加一条边

    第二种操作是回答是否能经过彩虹边从$a$节点到达$b$节点

    数据范围:

    $2 le n le 10^5$
    $1 le m,q le 10^5$

    分析: 

    我们可以考虑用并查集把那些可以互相到达(经过边数为偶数的彩虹路)的点对用并查集连接起来

    当$a-b-c$的边的颜色相同时,我们把a和c节点用并查集连接起来,代表$a$和$c$互连

    对于节点a,每个颜色的边只需要保存一条,这样可以快速合并节点

    这样,两个点是否能到达,只需要判断他们的并查集根是不是相同

    但是还有一种情况,$x$节点到$y$节点经过的边数为奇数,这样最后一条边的颜色就不重要了

    我们可以给每个并查集添加一个集合,集合里面的点直接连接某个并查集的点

    连接两个并查集用到了启发式合并(整个合并操作复杂度为$O(nlgn)$)

    ac代码:

    #include<bits/stdc++.h>
    #define ll long long
    #define ull unsigned long long
    #define pa pair<int,int>
    using namespace std;
    const int maxn=1e5+10;
    const int maxm=5e6+10;
    const ll mod=1e9+7;
    map<int,int>ma[maxn];//对于节点a,每个颜色的边只需要保存一条
    set<int>se[maxn];
    int n,m,c,q,boss[maxn];
    void inti()
    {
        for(int i=1;i<=n;i++)
            boss[i]=i;
    }
    int fin(int x)
    {
        if(boss[x]==x)return x;
        return boss[x]=fin(boss[x]);
    }
    void uni(int a,int b)
    {
        int v1=fin(a),v2=fin(b);
        if(v1==v2)return;
        if(se[v1].size()>se[v2].size())swap(v1,v2);//启发式合并关键
        boss[v1]=v2;
        for(auto i :se[v1])se[v2].insert(i);
        se[v1].clear();
    }
    void add_edge()
    {
        int a,b,v;
        scanf("%d %d %d",&a,&b,&v);
        if(ma[a].count(v))
            uni(ma[a][v],b);
        else
            ma[a][v]=b;
        if(ma[b].count(v))
            uni(ma[b][v],a);
        else
            ma[b][v]=a;
        se[fin(a)].insert(b);
        se[fin(b)].insert(a);
    }
    int main()
    {
        scanf("%d %d %d %d",&n,&m,&c,&q);
        inti();
        for(int i=1; i<=m; i++)
            add_edge();
        while(q--)
        {
            getchar();
            if(getchar()=='?')
            {
                int fla=0,a,b;
                scanf("%d %d",&a,&b);
                int v=fin(a);
                if(v==fin(b)||se[v].find(b)!=se[v].end())//同一个集合,或者不同集合,但是再走一条边能到
                     printf("Yes
    ");
                else
                     printf("No
    ");
            }
            else
            {
                add_edge();
            }
        }
        return 0;
    }
    

      

  • 相关阅读:
    Byobu(tmux)的使用与定制
    Centos 编译安装Python 2.6
    how to set up the remote accout who to connection and management mysql server
    CentOS安装python2.6以及MySQLpython
    byobu "屏风" 简介 ,以及在CentOS下安装及日常使用
    /bin/rm: cannot remove `libtoolT': No such file or directory
    MySQLpython EnvironmentError: mysql_config not found | InfoEntropy
    几个逼真的页面 watch out
    Emerge详细解释
    微软Internet TV初体验
  • 原文地址:https://www.cnblogs.com/carcar/p/10902142.html
Copyright © 2020-2023  润新知