Atcoder 2159 連結 / Connectivity(并查集+map乱搞)

問題文
N 個の都市があり、K 本の道路と L 本の鉄道が都市の間に伸びています。 i 番目の道路は pi 番目と qi 番目の都市を双方向に結び、 i 番目の鉄道は ri 番目と si 番目の都市を双方向に結びます。 異なる道路が同じ 2 つの都市を結ぶことはありません。同様に、異なる鉄道が同じ 2 つの都市を結ぶことはありません。

ある都市から別の都市に何本かの道路を通って到達できるとき、それらの都市は道路で連結しているとします。また、すべての都市はそれ自身と道路で連結しているとみなします。
鉄道についても同様に定めます。

全ての都市について、その都市と道路・鉄道のどちらでも連結している都市の数を求めてください。

制約
2≦N≦2*105
1≦K,L≦105
1≦pi,qi,ri,si≦N
pi<qi
ri<si
i≠j のとき、(pi,qi)≠(pj,qj)
i≠j のとき、(ri,si)≠(rj,sj)
入力
入力は以下の形式で標準入力から与えられる。

N K L
p1 q1
:
pK qK
r1 s1
:
rL sL
出力
N 個の整数を出力せよ。i 番目の数は i 番目の都市と道路・鉄道の両方で連結している都市の数である。

入力例 1
4 3 1
1 2
2 3
3 4
2 3
出力例 1
1 2 2 1
1,2,3,4 番目の都市は全て互いに道路で連結しています。

鉄道で連結している都市は 2,3 のみなので、答えは順に 1,2,2,1 となります。

入力例 2
4 2 2
1 2
2 3
1 4
2 3
出力例 2
1 2 2 1
入力例 3
7 4 4
1 2
2 3
2 5
6 7
3 5
4 5
3 4
6 7
出力例 3
1 1 2 1 2 2 2

题意:给出n个点,k条公路,l条铁路,构成一张无向图。定义i-j如果既能只通过铁路到达又能通过公路到达,则f[i]++とf[j]++,输出f[i](1<=i<=n)

题解:将只保留公路的图称之为A,只保留铁路的称之为B,AB均由一些内部可以两两互相到达的点集组成,假设点x在A集的第i个点集中,点x在B集的第j个点集中,则能对点x产生贡献的是所有在A中i集和B中j集的所有点个数,这可以用并查集维护。

代码如下:

#include<map>
#include<ctime>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define mp make_pair
using namespace std;

map<pair<int,int>,int> m;

struct dsu
{
    int fa[200010],rank[200010];
    
    void init(int n)
    {
        for(int i=1;i<=n;i++)
        {
            fa[i]=i;
        }
    }
    
    int find(int x)
    {
        if(fa[x]==x)
        {
            return x;
        }
        return fa[x]=find(fa[x]);
    }
    
    void union_(int x,int y)
    {
        int fx=find(x);
        int fy=find(y);
        if(fx==fy)
        {
            return ;
        }
        if(rank[fx]<rank[fy])
        {
            fa[fx]=fy;
        }
        else
        {
            fa[fy]=fx;
            if(rank[fx]==rank[fy])
            {
                rank[x]++;
            }
        }
    }
    
    int same(int x,int y)
    {
        return find(x)==find(y);
    }
}a,b;

int main()
{
    //give the fucking vjudge a flying fucking
    int n,x,y;
    scanf("%d%d%d",&n,&x,&y);
    a.init(n);
    b.init(n);
    int from,to;
    for(int i=1;i<=x;i++)
    {
        scanf("%d%d",&from,&to);
        a.union_(from,to);
    }
    for(int i=1;i<=y;i++)
    {
        scanf("%d%d",&from,&to);
        b.union_(from,to);
    }
    for(int i=1;i<=n;i++)
    {
        m[mp(a.find(i),b.find(i))]++;
    }
    for(int i=1;i<=n;i++)
    {
        printf("%d ",m[mp(a.find(i),b.find(i))]);
    }
}
原文地址:https://www.cnblogs.com/stxy-ferryman/p/9015882.html