Codeforces 859E Desk Disorder:並查集【兩個屬性二選一】

Leohh發表於2018-02-26

題目連結:http://codeforces.com/problemset/problem/859/E

題意:

  有n個人,2n個座位。

  給出這n個人初始的座位,和他們想坐的座位。

  每個人要麼坐在原來的位置不動,要麼坐到想坐的座位上,但是不能有兩個人坐在同一個座位上。

  問你合法的安排座位的方案數。

 

題解:

  將2n個座位抽象成2n個點。

  對於每個人,從他的初始位置向想坐的位置連一條邊。

  總答案即為所有連通塊答案的乘積。

  由於每一個點最多向外連一條邊,所以對於每一個連通塊只有三種情況:

    (1)是一棵樹,根節點不自環,且所有邊的方向都是由兒子指向父親。

    (2)是一棵樹,根節點自環,且所有邊的方向都是由兒子指向父親。

    (3)有且只有一個環。

  對於這三種情況,可以發現:

    (1)方案數 = 連通塊大小siz[fa]

    (2)方案數 = 1

    (3)方案數 = 2

  並查集維護一下,最後統計答案即可。

 

AC Code:

 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #include <algorithm>
 5 #define MAX_N 200005
 6 #define MOD 1000000007
 7 
 8 using namespace std;
 9 
10 int n;
11 int par[MAX_N];
12 int siz[MAX_N];
13 bool tag[MAX_N];
14 bool loop[MAX_N];
15 long long ans=1;
16 
17 void init_union_find()
18 {
19     for(int i=1;i<=(n<<1);i++)
20     {
21         par[i]=i;
22         siz[i]=1;
23         tag[i]=false;
24         loop[i]=false;
25     }
26 }
27 
28 int find(int x)
29 {
30     return par[x]==x ? x : par[x]=find(par[x]);
31 }
32 
33 void unite(int x,int y)
34 {
35     int px=find(x);
36     int py=find(y);
37     if(px==py)
38     {
39         tag[px]=true;
40         return;
41     }
42     siz[py]+=siz[px];
43     tag[py]|=tag[px];
44     par[px]=py;
45 }
46 
47 void read()
48 {
49     cin>>n;
50     init_union_find();
51     int x,y;
52     for(int i=1;i<=n;i++)
53     {
54         cin>>x>>y;
55         unite(x,y);
56         if(x==y) loop[x]=true;
57     }
58 }
59 
60 void work()
61 {
62     for(int i=1;i<=(n<<1);i++)
63     {
64         if(find(i)==i)
65         {
66             if(loop[i]) continue;
67             if(tag[i]) ans=(ans<<1ll)%MOD;
68             else ans=ans*siz[i]%MOD;
69         }
70     }
71     cout<<ans<<endl;
72 }
73 
74 int main()
75 {
76     read();
77     work();
78 }

 

相關文章