• kuangbin带我飞QAQ 并查集


      1. POJ 2236

      给出N个点,一开始图是空白的,两个操作,一个是增加一个点(给出坐标),一个是查询两个点间是否相通,当两点间的距离小于D或者两点通过其他点间接相连时说这两个点相通。并查集维护,每次增加一个点加入到vector中并于之前的点比较,距离小于D则合并到一个集合即可。

     1 #include <iostream>
     2 #include <string.h>
     3 #include <cstdio>
     4 #include <vector>
     5 #include <string>
     6 #include <algorithm>
     7 #include <math.h>
     8 #include <time.h>
     9 
    10 #define SIGMA_SIZE 26
    11 #define lson rt<<1
    12 #define rson rt<<1|1
    13 #pragma warning ( disable : 4996 )
    14 
    15 using namespace std;
    16 typedef long long LL;
    17 inline LL LMax(LL a,LL b)      { return a>b?a:b; }
    18 inline LL LMin(LL a,LL b)      { return a>b?b:a; }
    19 inline int Max(int a,int b)    { return a>b?a:b; }
    20 inline int Min(int a,int b)       { return a>b?b:a; }
    21 inline int gcd( int a, int b ) { return b==0?a:gcd(b,a%b); }
    22 inline int lcm( int a, int b ) { return a/gcd(a,b)*b; }  //a*b = gcd*lcm
    23 const LL INF = 0x3f3f3f3f3f3f3f3f;
    24 const LL mod  = 1000000007;
    25 const double eps = 1e-8;
    26 const int inf  = 0x3f3f3f3f;
    27 const int maxk = 1005;
    28 const int maxn = 1030;
    29 
    30 int N, D;
    31 vector<int> alive;
    32 bool vis[maxk];
    33 int root[maxk];
    34 int xi[maxk], yi[maxk];
    35 
    36 
    37 int find( int x )
    38 { return x==root[x] ? x : root[x]=find(root[x]); }
    39 
    40 void join( int x, int y )
    41 {
    42     x = find(x); y = find(y);
    43     if ( x == y )
    44         return;
    45     root[x] = y;
    46 }
    47 
    48 int getDist( int i, int j )
    49 { return (xi[i]-xi[j])*(xi[i]-xi[j]) + (yi[i]-yi[j])*(yi[i]-yi[j]) ; }
    50 
    51 void init()
    52 {
    53     alive.clear();
    54     memset(vis, 0, sizeof(vis) );
    55 
    56     for ( int i = 0; i < maxk; i++ )
    57         root[i] = i;
    58 
    59     for ( int i = 1; i <= N; i++ )
    60         scanf( "%d %d", &xi[i], &yi[i] );
    61 }
    62 
    63 int main()
    64 {
    65     freopen("F:\cpp\test.txt", "r", stdin );
    66     scanf("%d %d", &N, &D);
    67     init();
    68 
    69     int x, y;
    70     char str[5];
    71     while ( ~scanf("%s", str) )
    72     {
    73         if ( str[0] == 'O' )
    74         {
    75             scanf("%d", &x);
    76             vis[x] = true;
    77             alive.push_back(x);
    78 
    79             for ( int i = 0; i < alive.size()-1; i++ )
    80                 if ( getDist(alive[i], x) <= D*D )
    81                     join(alive[i], x);
    82         }
    83         else
    84         {
    85             scanf("%d %d", &x, &y);
    86             if ( (!vis[x]) || (!vis[y]) )
    87                 printf("FAIL
    ");
    88             else
    89             {
    90                 x = find(x); y = find(y);
    91                 if ( x == y )
    92                     printf("SUCCESS
    ");
    93                 else
    94                     printf("FAIL
    ");
    95             }
    96         }
    97     }
    98 }
    View Code

       2. HDU 1213

      并查集裸题,给N个点和M个关系,问最终有多少个集合

     1 #include <iostream>
     2 #include <string.h>
     3 #include <cstdio>
     4 #include <vector>
     5 #include <string>
     6 #include <algorithm>
     7 #include <math.h>
     8 #include <time.h>
     9 
    10 #define SIGMA_SIZE 26
    11 #define lson rt<<1
    12 #define rson rt<<1|1
    13 #pragma warning ( disable : 4996 )
    14 
    15 using namespace std;
    16 typedef long long LL;
    17 inline LL LMax(LL a,LL b)      { return a>b?a:b; }
    18 inline LL LMin(LL a,LL b)      { return a>b?b:a; }
    19 inline int Max(int a,int b)    { return a>b?a:b; }
    20 inline int Min(int a,int b)       { return a>b?b:a; }
    21 inline int gcd( int a, int b ) { return b==0?a:gcd(b,a%b); }
    22 inline int lcm( int a, int b ) { return a/gcd(a,b)*b; }  //a*b = gcd*lcm
    23 const LL INF = 0x3f3f3f3f3f3f3f3f;
    24 const LL mod  = 1000000007;
    25 const double eps = 1e-8;
    26 const int inf  = 0x3f3f3f3f;
    27 const int maxk = 1005;
    28 const int maxn = 1030;
    29 
    30 int N, M;
    31 bool vis[maxk];
    32 int root[maxk];
    33 
    34 int find( int x )
    35 { return x==root[x] ? x : root[x]=find(root[x]); }
    36 
    37 void join( int x, int y )
    38 {
    39     x = find(x); y = find(y);
    40     if ( x == y )
    41         return;
    42     root[x] = y;
    43 }
    44 
    45 void init()
    46 {
    47     memset( vis, 0, sizeof(vis) );
    48     for ( int i = 0; i < maxk; i++ )
    49         root[i] = i;
    50 }
    51 
    52 int main()
    53 {
    54     //freopen("F:\cpp\test.txt", "r", stdin );
    55     
    56     int T; cin >> T;
    57     while (T--)
    58     {
    59         int cnt = 0;
    60         int x, y;
    61 
    62         init();
    63         scanf("%d %d", &N, &M);
    64 
    65         for ( int i = 1; i <= M; i++ )
    66         {
    67             scanf("%d %d", &x, &y);
    68             join(x,y);
    69         }
    70 
    71         for ( int i = 1; i <= N; i++ )
    72             vis[find(i)] = true;
    73         for ( int i = 1; i <= N; i++ )
    74             if (vis[i])
    75                 cnt++;
    76         printf("%d
    ", cnt);
    77     }
    78 
    79     return 0;
    80 }
    View Code

       3.HDU 3038 

      和一道经典的题目(就是下一道)食物链很像,记得某场比赛做过类似的,当时以为是线段树各种做不出,,,结果发现原来是并查集

      给一组数列,数字未知,给出A,B和[A,B]表示A到B这段子数列内的数字和,这样按顺序给出来,问你有多少个逻辑错误,遇到错误则跳过该错误。

      比如给了[1,4] = 5, [1,2] = 3,这个时候再给一个[3,4]=6,那么这一行明显和前面得到的条件矛盾,所以错误数加一并且跳过这一行,具体是用向量操作,可以参考这两篇博客:

      https://www.cnblogs.com/liyinggang/p/5327055.html

      https://blog.csdn.net/niushuai666/article/details/6981689

     1 #include <iostream>
     2 #include <string.h>
     3 #include <cstdio>
     4 #include <vector>
     5 #include <string>
     6 #include <algorithm>
     7 #include <math.h>
     8 #include <time.h>
     9 
    10 #define SIGMA_SIZE 26
    11 #define lson rt<<1
    12 #define rson rt<<1|1
    13 #pragma warning ( disable : 4996 )
    14 
    15 using namespace std;
    16 typedef long long LL;
    17 inline LL LMax(LL a,LL b)      { return a>b?a:b; }
    18 inline LL LMin(LL a,LL b)      { return a>b?b:a; }
    19 inline int Max(int a,int b)    { return a>b?a:b; }
    20 inline int Min(int a,int b)       { return a>b?b:a; }
    21 inline int gcd( int a, int b ) { return b==0?a:gcd(b,a%b); }
    22 inline int lcm( int a, int b ) { return a/gcd(a,b)*b; }  //a*b = gcd*lcm
    23 const LL INF = 0x3f3f3f3f3f3f3f3f;
    24 const LL mod  = 1000000007;
    25 const double eps = 1e-8;
    26 const int inf  = 0x3f3f3f3f;
    27 const int maxk = 1005;
    28 const int maxn = 2e5+5;
    29 
    30 int root[maxn];
    31 int sum[maxn];
    32 
    33 int _find( int x )
    34 {
    35      int fa = root[x];
    36 
    37      if ( x == root[x] )
    38          return x;
    39 
    40     root[x] = _find(fa);
    41     sum[x] += sum[fa];
    42 
    43     return root[x];
    44 }
    45 
    46 void init( int n )
    47 {
    48     for ( int i = 0; i <= n; i++ )
    49     {
    50         root[i] = i;
    51         sum[i] = 0;
    52     }
    53 }
    54 
    55 int main()
    56 {
    57     //freopen("F:\cpp\test.txt", "r", stdin );
    58 
    59     int N, M, cnt;
    60     while (cin >> N >> M)
    61     {
    62         init(N);
    63 
    64         cnt = 0;
    65         int x, y, val;
    66         int xr, yr;
    67         while ( M-- )
    68         {
    69             scanf("%d %d %d", &x, &y, &val);
    70             
    71             x--;
    72             xr = _find(x); yr = _find(y);
    73             if ( xr == yr )
    74             {
    75                 if ( val != sum[x] - sum[y] )
    76                     cnt++;
    77             }
    78             else
    79             {
    80                 root[xr] = yr;
    81                 sum[xr] = sum[y]-sum[x]+val;
    82             }
    83         }
    84 
    85         printf("%d
    ", cnt);
    86     }
    87 
    88     return 0;
    89 }
    View Code

       4. HDU 1272

      POJ日常抽风,只能跑来做HDU的题目了233,实际上就是给定一个图让你判断是不是一颗连通树,所以有两个条件:无环,连通。无环用并查集判断,如果有两个点都在同一并查集,则说明肯定有环了。连通可以用(在无环的情况下)点数=边数+1判断,也可以用最后算出来总共只有一个集合来判断。坑爹的是要考虑空树,也就是直接给0 0的情况...

      1 #include <iostream>
      2 #include <string.h>
      3 #include <cstdio>
      4 #include <vector>
      5 #include <set>
      6 #include <string>
      7 #include <algorithm>
      8 #include <math.h>
      9 #include <time.h>
     10 
     11 #define SIGMA_SIZE 26
     12 #define lson rt<<1
     13 #define rson rt<<1|1
     14 #pragma warning ( disable : 4996 )
     15 
     16 using namespace std;
     17 typedef long long LL;
     18 inline LL LMax(LL a,LL b)      { return a>b?a:b; }
     19 inline LL LMin(LL a,LL b)      { return a>b?b:a; }
     20 inline int Max(int a,int b)    { return a>b?a:b; }
     21 inline int Min(int a,int b)       { return a>b?b:a; }
     22 inline int gcd( int a, int b ) { return b==0?a:gcd(b,a%b); }
     23 inline int lcm( int a, int b ) { return a/gcd(a,b)*b; }  //a*b = gcd*lcm
     24 const LL INF = 0x3f3f3f3f3f3f3f3f;
     25 const LL mod  = 1000000007;
     26 const double eps = 1e-8;
     27 const int inf  = 0x3f3f3f3f;
     28 const int maxk = 1005;
     29 const int maxn = 1e5+5;
     30 
     31 
     32 int root[maxn];
     33 set<int> num;
     34 
     35 int _find(  int x )  
     36 { return x==root[x] ? x : root[x]=_find(root[x]); }  
     37 
     38 void merge( int x, int y )
     39 {
     40     x = _find(x); y = _find(y);
     41     if ( x == y )
     42         return;
     43     root[x] = y;
     44 }
     45 
     46 void init()
     47 {
     48     num.clear();
     49     for ( int i = 0; i < maxn; i++ )
     50         root[i] = i;
     51 }
     52 
     53 int main()
     54 {
     55     //freopen("F:\cpp\test.txt", "r", stdin );
     56 
     57     int x, y;
     58     while (1)
     59     {
     60         int cnt = 0;
     61         bool ok = true;
     62         init();
     63 
     64         scanf("%d %d", &x, &y);
     65         if ( x == -1 ) 
     66             break;
     67         if ( x == 0 )
     68         {
     69             printf("Yes
    ");
     70             continue;
     71         }
     72         merge(x,y);
     73         num.insert(x); num.insert(y);
     74         cnt++;
     75 
     76         while (1)
     77         {
     78             scanf("%d %d", &x, &y);
     79             if ( x == 0 ) 
     80                 break;
     81             num.insert(x); num.insert(y);
     82             cnt++;
     83 
     84             if (ok)
     85             {
     86                 x = _find(x); y = _find(y);
     87                 if ( x == y )
     88                     ok = false;
     89 
     90                 merge(x, y);
     91             }
     92         }
     93 
     94         if ( ok && num.size() == cnt+1 )
     95             printf("Yes
    ");
     96         else
     97             printf("No
    ");
     98     }
     99     return 0;
    100 }
    View Code

       

      5. ZOJ 3261

      思路简单,写起来麻烦...大意是给N个点M条边,每个点有一个power值。然后有两个操作,一是毁灭其中一条边,二是询问一个点A,求与A直接或间接相连的所有点中power值最大的那个,且求出来的power值需大于A的power值,当有多个点power值相同,取序号最小那个。

      显然并查集不支持删除,所以需要逆向操作,先按顺序存储所有操作,做出删完所有该删的边的最终图,再从后往前加边,询问。

      询问操作比较好存,毁灭操作就难一点了,这里我用了map,因为map搜索是log级别的,即使要搜两边(x y和y x)也很快。其他除了并查集merge的时候要注意点就没什么了,就是写的好慢...

      1 #include <iostream>
      2 #include <string.h>
      3 #include <cstdio>
      4 #include <vector>
      5 #include <map>
      6 #include <string>
      7 #include <algorithm>
      8 #include <math.h>
      9 #include <time.h>
     10 
     11 #define SIGMA_SIZE 26
     12 #define lson rt<<1
     13 #define rson rt<<1|1
     14 #pragma warning ( disable : 4996 )
     15 
     16 using namespace std;
     17 typedef long long LL;
     18 inline LL LMax(LL a,LL b)      { return a>b?a:b; }
     19 inline LL LMin(LL a,LL b)      { return a>b?b:a; }
     20 inline int Max(int a,int b)    { return a>b?a:b; }
     21 inline int Min(int a,int b)       { return a>b?b:a; }
     22 inline int gcd( int a, int b ) { return b==0?a:gcd(b,a%b); }
     23 inline int lcm( int a, int b ) { return a/gcd(a,b)*b; }  //a*b = gcd*lcm
     24 const LL INF = 0x3f3f3f3f3f3f3f3f;
     25 const LL mod  = 1000000007;
     26 const double eps = 1e-8;
     27 const int inf  = 0x3f3f3f3f;
     28 const int maxk = 1005;
     29 const int maxn = 1e4+5;
     30 
     31 //struct edge {
     32 //    int to, next;
     33 //}e[4*maxn];
     34 
     35 map<pair<int,int>,bool> mmap;
     36 map<pair<int,int>,bool>::iterator itor;
     37 
     38 int xi[5*maxn], yi[5*maxn], query[5*maxn];
     39 int root[maxn], val[maxn];
     40 int N, M, Q, death_num;
     41 
     42 
     43 //void addedge( int u, int v )
     44 //{ e[cnt].to = v; e[cnt].next = linjie[u]; linjie[u] = cnt++; }
     45 
     46 int _find( int x )
     47 { return x==root[x] ? x : root[x]=_find(root[x]); }
     48 
     49 void merge( int x, int y )
     50 {
     51     x = _find(x); y = _find(y);
     52     if ( x == y )
     53         return;
     54 
     55     //让 x < y
     56     if ( x > y ) swap(x,y);
     57 
     58     if ( val[x] > val[y] ) root[y] = x;
     59     else if ( val[x] < val[y] ) root[x] = y;
     60     else root[y] = x;
     61 }
     62 
     63 void init( int n )
     64 {
     65     death_num = 0; 
     66     mmap.clear();
     67 
     68     //memset( linjie, -1, sizeof(linjie) );
     69     for ( int i = 0; i <= n; i++ )
     70         root[i] = i;
     71 }
     72 
     73 void read( int n )
     74 {
     75     //读入power
     76     for ( int i = 0; i < n; i++ )
     77         scanf("%d", &val[i]);
     78     
     79     //读入边
     80     cin >> M;
     81     int x, y;
     82     for ( int i = 0; i < M; i++ )
     83     {
     84         scanf("%d %d", &x, &y);
     85         mmap.insert( make_pair(make_pair(x,y), true) );
     86     }
     87 
     88     //读入query
     89     cin >> Q;
     90     char str[10];
     91     for ( int i = 0; i < Q; i++ )
     92     {
     93         scanf("%s", str);
     94         if ( str[0] == 'q' )
     95         {
     96             scanf("%d", &x);
     97             query[i] = x;
     98         }
     99         else
    100         {
    101             //依次读入被毁灭的边,然后在mmap中寻找并变为false
    102             scanf("%d %d", &xi[death_num], &yi[death_num]);
    103             itor = mmap.find(make_pair(xi[death_num],yi[death_num]));
    104             if ( itor != mmap.end() )
    105                 (*itor).second = false;
    106             else
    107             {
    108                 itor = mmap.find(make_pair(yi[death_num],xi[death_num]));
    109                 (*itor).second = false;
    110             }
    111 
    112             death_num++;
    113             query[i] = -2;
    114         }
    115     }
    116 }
    117 
    118 void make_map()
    119 {
    120     int x, y;
    121 
    122     //如果该边没有被毁灭
    123     for ( itor = mmap.begin(); itor != mmap.end(); itor++ )
    124         if ( (*itor).second )
    125         {
    126             x = ((*itor).first).first; y = ((*itor).first).second;
    127             //addedge( x, y );
    128             //addedge( y, x );
    129             merge( x, y );
    130         }
    131 }
    132 
    133 void solve()
    134 {
    135     int tmp;
    136     for ( int i = Q-1; i >= 0; i-- )
    137     {    
    138                                         
    139         if ( query[i] != -2 )                //如果是询问
    140         {
    141             tmp = _find(query[i]);
    142             if ( val[tmp] <= val[query[i]] )
    143                 query[i] = -1;
    144             else
    145                 query[i] = tmp;
    146         }
    147         else
    148         {
    149             death_num--;
    150             merge(xi[death_num], yi[death_num]);
    151         }
    152     }
    153 }
    154 
    155 int main()
    156 {
    157     //freopen("F:\cpp\test.txt", "r", stdin );
    158 
    159     int cnt = 0;
    160     while ( ~scanf("%d", &N) )
    161     {
    162         if ( cnt )
    163             printf("
    ");
    164         init(N);
    165         read(N);
    166         make_map();
    167         solve();
    168         for ( int i = 0; i < Q; i++ )
    169             if ( query[i] != -2)
    170                 printf("%d
    ", query[i]);
    171         cnt++;
    172     }
    173 
    174     return 0;
    175 }
    View Code

       

      6. POJ 2492

      并查集做这种题实在太好了,这道题像是食物链的弱化版,给N个虫子,只有异性间才会交配.....给M个交配方案,看看虫子里面有没有同性恋(笑)这个关系还是比较简单的,用0表示两虫子同性,1表示虫子异性,rela[i]表示i和根节点的关系。

    三个虫子中有三种关系(A-B, B-C, C-A)只要知道其中两种,很容易推出第三种,然后推出的关系维护并查集,具体看代码,很简单

      1 #include <iostream>
      2 #include <string.h>
      3 #include <cstdio>
      4 #include <vector>
      5 #include <map>
      6 #include <string>
      7 #include <algorithm>
      8 #include <math.h>
      9 #include <time.h>
     10 
     11 #define SIGMA_SIZE 26
     12 #define lson rt<<1
     13 #define rson rt<<1|1
     14 #pragma warning ( disable : 4996 )
     15 
     16 using namespace std;
     17 typedef long long LL;
     18 inline LL LMax(LL a,LL b)      { return a>b?a:b; }
     19 inline LL LMin(LL a,LL b)      { return a>b?b:a; }
     20 inline int Max(int a,int b)    { return a>b?a:b; }
     21 inline int Min(int a,int b)       { return a>b?b:a; }
     22 inline int gcd( int a, int b ) { return b==0?a:gcd(b,a%b); }
     23 inline int lcm( int a, int b ) { return a/gcd(a,b)*b; }  //a*b = gcd*lcm
     24 const LL INF = 0x3f3f3f3f3f3f3f3f;
     25 const LL mod  = 1000000007;
     26 const double eps = 1e-8;
     27 const int inf  = 0x3f3f3f3f;
     28 const int maxk = 1e6+5;
     29 const int maxn = 2005;
     30 
     31 //rela[i]表示i与其根的关系 为0表示同性,为1表示异性
     32 int root[maxn];
     33 bool rela[maxn];
     34 int N, Q;
     35 
     36 void init()
     37 {
     38     scanf("%d %d", &N, &Q);
     39 
     40     memset( rela, 0, sizeof(rela) );
     41     for ( int i = 0; i <= N; i++ )
     42         root[i] = i;
     43 }
     44 
     45 bool getRela( bool master, bool minor )
     46 {
     47     //如果两者关系为异性,则第三条关系相反
     48     if ( master )
     49         return (!minor);
     50     else
     51         return minor;
     52 }
     53 
     54 int _find( int x )
     55 { 
     56     int r = x, pre = root[x];
     57     if ( r == root[r] )
     58         return root[r];
     59 
     60     r = _find(root[r]);
     61     root[x] = r;
     62     rela[x] = getRela( rela[x], rela[pre] );
     63 
     64     return root[x];
     65 }
     66 
     67 void merge( int x, int y, int xr, int yr )
     68 {
     69     //tmp是y和xr的关系
     70     bool tmprela = getRela( true, rela[x] );
     71     root[xr] = yr;
     72     rela[xr] = getRela( tmprela, rela[y] );
     73 }
     74 
     75 int main()
     76 {
     77     //freopen("F:\cpp\test.txt", "r", stdin );
     78 
     79     int T; cin >> T;
     80     int CNT = 1;
     81     while (T--)
     82     {
     83         bool nobug = true;
     84         int x, y, xr, yr;
     85 
     86         init();
     87         while (Q--)
     88         {
     89             scanf("%d %d", &x, &y);
     90             if (nobug)
     91             {
     92                 xr = _find(x); yr = _find(y);
     93                 if ( xr == yr )
     94                 {
     95                     if ( rela[x] != getRela(true, rela[y]) )
     96                         nobug = false;
     97                 }
     98                 else
     99                     merge(x, y, xr, yr);
    100             }
    101         }
    102         printf("Scenario #%d:
    ", CNT++);
    103         if ( nobug )
    104             printf("No suspicious bugs found!
    ");
    105         else
    106             printf("Suspicious bugs found!
    ");
    107         printf("
    ");
    108     }
    109 
    110     return 0;
    111 }
    View Code

       

      7.POJ 1182

      食物链,经典题目,有了前面的铺垫这道题就算是硬算也不难,前面几题集合中只有两种关系,这里就有三种关系,本质上是向量+偏移量,懂了还是不难的

      PS:这道题只能单次输入,如果加了while循环输入就会WA...完全不知道为什么,害我查了一个小时的bug......

     1 #include <iostream>
     2 #include <string.h>
     3 #include <cstdio>
     4 #include <vector>
     5 #include <map>
     6 #include <string>
     7 #include <algorithm>
     8 #include <math.h>
     9 #include <time.h>
    10 
    11 #define SIGMA_SIZE 26
    12 #define lson rt<<1
    13 #define rson rt<<1|1
    14 #pragma warning ( disable : 4996 )
    15 
    16 using namespace std;
    17 typedef long long LL;
    18 inline LL LMax(LL a,LL b)      { return a>b?a:b; }
    19 inline LL LMin(LL a,LL b)      { return a>b?b:a; }
    20 inline int Max(int a,int b)    { return a>b?a:b; }
    21 inline int Min(int a,int b)       { return a>b?b:a; }
    22 inline int gcd( int a, int b ) { return b==0?a:gcd(b,a%b); }
    23 inline int lcm( int a, int b ) { return a/gcd(a,b)*b; }  //a*b = gcd*lcm
    24 const LL INF = 0x3f3f3f3f3f3f3f3f;
    25 const LL mod  = 1000000007;
    26 const double eps = 1e-8;
    27 const int inf  = 0x3f3f3f3f;
    28 const int maxk = 1e6+5;
    29 const int maxn = 5e4+5;
    30 
    31 int root[maxn], rela[maxn];
    32 
    33 int _find( int x )
    34 {
    35     if ( x == root[x] )
    36         return x;
    37      
    38     int pre = root[x];
    39     root[x] = _find(root[x]);
    40     rela[x] = (rela[x] + rela[pre]) % 3;
    41 
    42     return root[x];
    43 }
    44 
    45 int main()
    46 {
    47     //freopen("F:\cpp\test.txt", "r", stdin );
    48     int N, K, cnt;
    49     scanf("%d %d", &N, &K);
    50     for ( int i = 0; i <= N; i++ )
    51         root[i] = i;
    52     cnt = 0;
    53     memset( rela, 0, sizeof(rela) );
    54 
    55         
    56     int d, x, y, xr, yr;
    57     while (K--)
    58     {
    59         scanf("%d %d %d", &d, &x, &y);
    60         d--;
    61 
    62         if ( x > N || y > N )
    63             { cnt++; continue; }
    64         if ( x == y && d == 1 )
    65             { cnt++; continue; }
    66 
    67         xr = _find(x); yr = _find(y);
    68         if ( xr == yr )
    69         {
    70             if ( d != ((rela[x] - rela[y] + 3)%3) )
    71                 cnt++;
    72         }
    73         else
    74         {
    75             root[xr] = yr;
    76             rela[xr] = (rela[y] + d - rela[x] + 3) % 3;
    77         }
    78     }
    79     printf("%d
    ", cnt);
    80 
    81     return 0;
    82 }
    View Code

       

      8.POJ 1611 The Suspects 

      并查集裸题,给M个组,每个组有N个学生,其中0号学生是感染者,和感染者同一组的都是感染者,所以只要求0号学生为根的集合的学生个数即可,merge时约定0号学生为根就可以了。

     1 #include <iostream>
     2 #include <string.h>
     3 #include <cstdio>
     4 #include <vector>
     5 #include <map>
     6 #include <string>
     7 #include <algorithm>
     8 #include <math.h>
     9 #include <time.h>
    10 
    11 #define SIGMA_SIZE 26
    12 #define lson rt<<1
    13 #define rson rt<<1|1
    14 #pragma warning ( disable : 4996 )
    15 
    16 using namespace std;
    17 typedef long long LL;
    18 inline LL LMax(LL a,LL b)      { return a>b?a:b; }
    19 inline LL LMin(LL a,LL b)      { return a>b?b:a; }
    20 inline int Max(int a,int b)    { return a>b?a:b; }
    21 inline int Min(int a,int b)       { return a>b?b:a; }
    22 inline int gcd( int a, int b ) { return b==0?a:gcd(b,a%b); }
    23 inline int lcm( int a, int b ) { return a/gcd(a,b)*b; }  //a*b = gcd*lcm
    24 const LL INF = 0x3f3f3f3f3f3f3f3f;
    25 const LL mod  = 1000000007;
    26 const double eps = 1e-8;
    27 const int inf  = 0x3f3f3f3f;
    28 const int maxk = 3e4+5;
    29 const int maxn = 5e4+5;
    30 
    31 int root[maxk], num[maxk];
    32 int N, M;
    33 
    34 void init()
    35 {
    36     for ( int i = 0; i <= N; i++ )
    37     {
    38         root[i] = i;
    39         num[i] = 1;
    40     }
    41 }
    42 
    43 int _find(int x)
    44 { return x==root[x] ? x : root[x] = _find(root[x]); }
    45 
    46 void merge( int x, int y )
    47 {
    48     int xr = _find(x);
    49     int yr = _find(y);
    50 
    51     if (xr != yr)
    52     {
    53         if (xr == 0)
    54         {
    55             root[yr] = xr;
    56             num[xr] = num[xr] + num[yr];
    57         }
    58         else
    59         {
    60             root[xr] = yr;
    61             num[yr] = num[xr]+num[yr];
    62         }
    63     }
    64 }
    65 
    66 int main()
    67 {
    68     while ( ~scanf("%d %d", &N, &M) )
    69     {
    70         if ( N == 0 && M == 0 )
    71             break;
    72 
    73         init();
    74 
    75         int x;
    76         for ( int j = 0; j < M; j++ )
    77         {
    78             int a, b;
    79 
    80             scanf("%d", &x);
    81             scanf("%d", &a);
    82             if ( x != 1 )
    83                 for (int i = 1; i <= x-1; i++)
    84                 {
    85                     scanf("%d", &b);
    86                     merge(a, b);
    87                     a = b;
    88 
    89                 }
    90         }
    91 
    92         printf("%d
    ", num[0]);
    93     }
    94 
    95     return 0;
    96 }
    View Code

       

      9. POJ 1417 True Liars

      村子里面有p1个好人p2个坏人,好人只会说真话,坏人只会说假话,现在可以问N个问题, 每个问题就是随机挑两人a和b,让a回答b是不是好人,然后让你判断出所有的好人。

      如果这道题只是求有没有矛盾,那就是一道很简单的带权并查集,和前面那个同性恋虫子思路一样。但现在问题是要求出所有好人,显然只根据问的N个问题是求不出来的,因为如果没有第一个能被确定为好人或者坏人的人,那么剩下所有人都是一个相对的关系,这样只能推断两个人是同为好人还是同为坏人或者一好一坏。经过简单的推算发现回答为yes时a和b为同类人,no时a与b异类,开个rela[i]数组表示i与根节点是同类还是异类, 这样带权并查集直接走起。

      那么我们可以用并查集先求出几个大集合,并且记录每个大集合A类人和B类人的个数,当然我们现在并不知道A类是好人还是坏人,只是一个相对的关系。显而易见我们应该在每个大集合各中抽取一个A类人或者B类人组成好人集合,如果好人集合人数正好为p1,并且这种选法唯一那我们就能确定所有好人了。比如只有一个大集合有4个A类人和4个B类人,而好人只有4个,那我们就不知道到底是A类是好人还是B类是好人了。实际上就像一个组合问题,看能否形成唯一的组合使其总数正好为p1,这点用dp很简单就能实现,dp[i][j]表示第i个大集合中使人数为j的方法最多有多少种,最后只要看dp[cnt][p1]是否等于1就可以了。

      然而这题最麻烦的还是记录路径,有一种方法是如果从dp[cnt][p1]往前推。因为dp[i][j]必然是由dp[i-1][j-A]和dp[i-1][j-B](A, B分别为某个大集合A类人和B类人的个数)推过来的,这两个dp只有一个为1,不然dp[i][j]就等于2了(有两种路径可以使好人人数达到 j ),所以只要将p1一步一步减回去看dp为1的那一类就是好人类。

      1 #include <iostream>
      2 #include <string.h>
      3 #include <cstdio>
      4 #include <vector>
      5 #include <map>
      6 #include <string>
      7 #include <algorithm>
      8 #include <time.h>
      9 
     10 #define SIGMA_SIZE 26
     11 #define lson rt<<1
     12 #define rson rt<<1|1
     13 #pragma warning ( disable : 4996 )
     14 
     15 using namespace std;
     16 typedef long long LL;
     17 inline LL LMax(LL a,LL b)      { return a>b?a:b; }
     18 inline LL LMin(LL a,LL b)      { return a>b?b:a; }
     19 inline int Max(int a,int b)    { return a>b?a:b; }
     20 inline int Min(int a,int b)       { return a>b?b:a; }
     21 inline int gcd( int a, int b ) { return b==0?a:gcd(b,a%b); }
     22 inline int lcm( int a, int b ) { return a/gcd(a,b)*b; }  //a*b = gcd*lcm
     23 const LL INF = 0x3f3f3f3f3f3f3f3f;
     24 const LL mod  = 1000000007;
     25 const double eps = 1e-8;
     26 const int inf  = 0x3f3f3f3f;
     27 const int maxk = 3e4+5;
     28 const int maxn = 600;
     29 
     30 
     31 int n, p1, p2, cnt;
     32 //num[i][0]表示该集合中与根节点i种类相同的人个数,反正亦然
     33 int num[602][2], root[602];
     34 //dp[i][j]表示前i的个大集合中天使人数为j的集合最多多少个
     35 int dp[602][602];
     36 int divide[602][2];
     37 bool rela[602]; //false表示与根为同类
     38 
     39 vector<int> ans, _list;
     40 vector<int> v0[602], v1[602];
     41 
     42 void init()
     43 {
     44     cnt = 1; ans.clear(); _list.clear();
     45     memset(num, 0, sizeof(num));
     46     memset(rela, 0, sizeof(rela));
     47     memset(dp, 0, sizeof(dp));
     48     for ( int i = 0; i <= p1+p2; i++ )
     49     {
     50         root[i] = i;
     51         num[i][0] = 1;
     52     }
     53 }
     54 
     55 int _find( int x )
     56 {
     57     if (x == root[x])
     58         return root[x];
     59 
     60     int pre = _find(root[x]);
     61 
     62     if (rela[root[x]])
     63         rela[x] = !rela[x];
     64     root[x] = pre;
     65 
     66     return pre;
     67 }
     68 
     69 void merge( int x, int y, bool link )
     70 {
     71     int xr = _find(x), yr = _find(y);
     72     if (xr == yr) 
     73         return;
     74 
     75     if (rela[x])
     76         link = !link;
     77     if (rela[y])
     78         rela[xr] = !link;
     79     else 
     80         rela[xr] = link;
     81 
     82     root[xr] = yr;
     83 
     84     //如果xr与yr是同类,则yr组中同类的数目要加上xr组中与xr同类的个数
     85     if (!rela[xr])
     86     {
     87         num[yr][0] += num[xr][0];
     88         num[yr][1] += num[xr][1];
     89     }
     90     else
     91     {
     92         num[yr][0] += num[xr][1];
     93         num[yr][1] += num[xr][0];
     94     }
     95 }
     96 
     97 void solve()
     98 {
     99     _list.push_back(0);
    100     for ( int i = 1; i <= p1+p2; i++ )
    101     {
    102         if ( _find(i) == i )
    103         {
    104             divide[cnt][0] = num[i][0];
    105             divide[cnt][1] = num[i][1];
    106             _list.push_back(i);
    107             cnt++;
    108         }
    109     }
    110 
    111     for ( int i = 1; i <= p1+p2; i++ )
    112     {
    113         int rt = root[i];
    114         if ( !rela[i] )
    115             v0[rt].push_back(i);
    116         else
    117             v1[rt].push_back(i);
    118     }
    119 
    120     //处理DP
    121     dp[0][0] = 1;
    122     for (int i = 1; i < cnt; i++)
    123     {
    124         int mmin = Min(divide[i][0], divide[i][1]);
    125         for (int j = p1; j >= mmin; j--)
    126         {
    127             dp[i][j] += dp[i-1][j-divide[i][0]];
    128             dp[i][j] += dp[i-1][j-divide[i][1]];
    129         }
    130     }
    131 
    132 
    133     if ( dp[cnt-1][p1] == 1 )
    134     {
    135         int tmp1 = p1, tmp2 = p2;
    136         for ( int i = cnt-1; i >= 1; i-- )
    137         {
    138             if ( tmp1-divide[i][0]>=0 && tmp2-divide[i][1]>=0 && dp[i-1][tmp1-divide[i][0]]==1 )
    139             {
    140                 int size = v0[_list[i]].size();
    141                 for ( int j = 0; j < size; j++ )
    142                     ans.push_back(v0[_list[i]][j]);
    143                 tmp1 -= divide[i][0];
    144                 tmp2 -= divide[i][1];
    145             }
    146             else if ( tmp1-divide[i][1]>=0 && tmp2-divide[i][0]>=0 && dp[i-1][tmp1-divide[i][1]]==1 )
    147             {
    148                 int size = v1[_list[i]].size();
    149                 for ( int j = 0; j < size; j++ )
    150                     ans.push_back(v1[_list[i]][j]);
    151                 tmp1 -= divide[i][1];
    152                 tmp2 -= divide[i][0];
    153             }
    154 
    155             v0[_list[i]].clear();
    156             v1[_list[i]].clear();
    157         }
    158         sort(ans.begin(), ans.end());
    159         for ( int i = 0; i < ans.size(); i++ )
    160             printf("%d
    ", ans[i]);
    161         printf("end
    ");
    162     }
    163     else
    164     {
    165         printf("no
    ");
    166         for ( int i = 1; i < _list.size(); i++ )
    167         {
    168             v0[_list[i]].clear();
    169             v1[_list[i]].clear();
    170         }
    171     }
    172 }
    173 
    174 int main()
    175 {
    176     while ( ~scanf("%d %d %d", &n, &p1, &p2) && n+p1+p2 )
    177     {
    178         init();
    179         int x, y;
    180         char str[5];
    181         bool link = false;    //false表示x与y是同类
    182 
    183         while (n--)
    184         {
    185             scanf("%d %d", &x, &y); scanf("%s", str);
    186             if (str[0] == 'n') link = true;
    187             else link = false;
    188 
    189             merge(x, y, link);
    190         }
    191 
    192         solve();
    193     }
    194 
    195     return 0;
    196 }
    View Code

       

      10. POJ 1733

      看上去是一道简单的种类并查集,但是关系并不好找,在网上看到一大神的思路,遂跪。

      对于[l,r],我们可以简单的设sum[l-1],sum[r]为0~l-1,0~r的前缀,这和前面种类并查集是一样的,然而这道题只给了你[l,r]之间1的个数为奇数或者偶数,这我半天都没反应过来怎么转换。其实可以这样想,如果[l,r]之间1个数为奇数,那么sum[l-1]^sum[r]就应该等于1,因为可以把sum[r]拆为0~l-1和l~r这两端,前面一段和sum[l-1]异或就变成零了,后面一段因为有奇数个1所以异或结果为1,同理如果[l,r]间1为偶数,那么最后就应该等于0。但这道题我们并不需要存sum,我们只要一个rela数组存奇偶关系, 所以每条向量(假设向量两个端点为x,y)的rela值就应该等于sum[x]^sum[y]。令三角向量三个端点为l-1, r, root,稍微推一下就知道怎么写了。

      1 #include <iostream>
      2 #include <string.h>
      3 #include <cstdio>
      4 #include <vector>
      5 #include <map>
      6 #include <string>
      7 #include <algorithm>
      8 #include <time.h>
      9 
     10 #define SIGMA_SIZE 26
     11 #define lson rt<<1
     12 #define rson rt<<1|1
     13 #pragma warning ( disable : 4996 )
     14 
     15 using namespace std;
     16 typedef long long LL;
     17 inline LL LMax(LL a,LL b)      { return a>b?a:b; }
     18 inline LL LMin(LL a,LL b)      { return a>b?b:a; }
     19 inline int Max(int a,int b)    { return a>b?a:b; }
     20 inline int Min(int a,int b)       { return a>b?b:a; }
     21 inline int gcd( int a, int b ) { return b==0?a:gcd(b,a%b); }
     22 inline int lcm( int a, int b ) { return a/gcd(a,b)*b; }  //a*b = gcd*lcm
     23 const LL INF = 0x3f3f3f3f3f3f3f3f;
     24 const LL mod  = 1000000007;
     25 const double eps = 1e-8;
     26 const int inf  = 0x3f3f3f3f;
     27 const int maxn = 2e4+5;
     28 
     29 
     30 //1个数为偶数则为0
     31 int rela[maxn];
     32 int root[maxn], num[maxn];
     33 int len, N, cnt, n;
     34 
     35 struct node {
     36     int lhs, rhs, rela;
     37 }lisan[maxn];
     38 
     39 int _find(int x)
     40 {
     41     if ( x == root[x] ) return root[x];
     42     int pre = _find(root[x]);
     43     rela[x] = rela[x]^rela[root[x]];
     44     root[x] = pre;
     45     return root[x];
     46 }
     47 
     48 void init()
     49 {
     50     cnt = 0;
     51     memset(rela, 0, sizeof(rela));
     52 }
     53 
     54 void read()
     55 {
     56     scanf("%d", &N);
     57     init();
     58     
     59     int x, y; char str[5];
     60     for (int i = 1; i <= N; i++ )
     61     {
     62         scanf("%d %d %s", &lisan[i].lhs, &lisan[i].rhs, str );
     63         lisan[i].rela = str[0]=='e' ? 0 : 1;
     64         num[++cnt] = lisan[i].lhs-1; num[++cnt] = lisan[i].rhs;
     65     }
     66 
     67     sort(num+1, num+1+cnt);
     68     n = unique(num+1, num+1+cnt)-num-1;
     69 }
     70 
     71 int main()
     72 {
     73     while (~scanf("%d", &len))
     74     {
     75         read();
     76 
     77         for ( int i = 0; i <= n; i++ )
     78             root[i] = i;
     79 
     80         int x, y, xr, yr;
     81         for ( int i = 1; i <= N; i++ )
     82         {
     83             x = lower_bound(num+1, num+1+n, lisan[i].lhs-1)-num;
     84             y = lower_bound(num+1, num+1+n, lisan[i].rhs)-num;
     85 
     86             xr = _find(x); yr = _find(y);
     87             if ( xr == yr )
     88             {
     89                 if ( rela[x]^rela[y] != lisan[i].rela )
     90                     { printf("%d
    ", i-1); return 0; }
     91             }
     92             else
     93             {
     94                 root[xr] = yr;
     95                 rela[xr] = rela[x]^rela[y]^lisan[i].rela;
     96             }
     97         }
     98         printf("%d", N);
     99     }
    100 
    101     return 0;
    102 }
    View Code
  • 相关阅读:
    两套经典的用户画像-梁宁
    准研一假期的减脂半自律计划
    网络科学导论【第六章】读书脑图
    常见规则网络
    网络科学导论【第五章】读书脑图
    复杂网络链路预测的研究现状及展望
    Python之@property详解及底层实现介绍
    Python触发异常
    一份较认可的文献阅读方案
    HITS算法简介
  • 原文地址:https://www.cnblogs.com/chaoswr/p/9125757.html
Copyright © 2020-2023  润新知