• 并查集专辑 (poj1182食物链,hdu3038, poj1733, poj1984, zoj3261)


    并查集专题训练地址,注册登录了才能看到题目

    并查集是一个树形的数据结构,  可以用来处理集合的问题, 也可以用来维护动态连通性,或者元素之间关系的传递(关系必须具有传递性才能有并查集来维护,因为并查集有压缩路径)。

    用并查集来维护元素之间关系的传递, 那么元素与元素之间就有一个权值(带权并查集),那么当路径压缩时,我们需要根据关系的传递性来维护

    当父元素变动时,关系的变动。

    poj1182食物链

    给定一些元素之间的关系, 问我们有多少是错误的。 当碰到一个错误时,并不会用它来更新并查集(错误的怎么用来更新?),只会把ans++

    我们用0表示与父亲是同类,  用1表示吃父亲 , 用2表示被父亲吃。(这表示的是我与父亲的关系,即箭头是由我指向父亲), 那怎么得到父亲与我的关系呢?

    只要将箭头的方向改变, 就得到了父亲与我的关系,  (3-rank[x]) % 3  就是了

     只要明白了箭头方向的改变,关系也可以用公式推导出来

    那么下边就好办了, 如果判断是否发生错误呢?

    如图,红色的线表示题目给我们的关系, 现在他们在一个集合里面,可以通过运算获得蓝线1,然后再通过计算获得蓝线2, 只要将蓝线2和红线对比,就知道

    题目所给的关系是否正确。

    同理,集合的合并也是一样的

    通过红线1,依次算出蓝线1,2,3.    那么就可以进行集合的合并了。

      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <stdlib.h>
      4 #include <algorithm>
      5 #include <iostream>
      6 #include <queue>
      7 #include <stack>
      8 #include <vector>
      9 #include <map>
     10 #include <set>
     11 #include <string>
     12 #include <math.h>
     13 using namespace std;
     14 #pragma warning(disable:4996)
     15 #pragma comment(linker, "/STACK:1024000000,1024000000")
     16 typedef long long LL;                   
     17 const int INF = 1<<30;
     18 /*
     19 路径压缩的时候要保留结点与结点之间的关系, 所以要维护的一个信息是,结点之间的关系
     20 0同类 ,  1被父亲吃,  2吃父亲
     21 */
     22 const int N = 50000 + 10;
     23 int fa[N];
     24 int id[N];//id[u] 表示与父亲之间的边的权值,, 权值为0,1,2三种
     25 int find(int x)
     26 {
     27     if (x == fa[x])
     28         return x;
     29     //路径压缩的时候,由于父亲的改变, 需要改变权值
     30     int tmp = fa[x];
     31     fa[x] = find(fa[x]);
     32     id[x] = (id[x] + id[tmp]) % 3;
     33     return fa[x];
     34 }
     35 int main()
     36 {
     37     int n, m, ans;
     38     int d, a, b;
     39     int fx, fy;
     40     //while (scanf("%d%d", &n, &m) != EOF)
     41     {
     42         scanf("%d%d", &n, &m);
     43         ans = 0;
     44         for (int i = 1; i <= n; ++i)
     45         {
     46             fa[i] = i;
     47             id[i] = 0;
     48         }
     49         while (m--)
     50         {
     51             scanf("%d%d%d", &d, &a, &b);
     52             if (d == 1)
     53             {
     54                 if (a > n || b > n)
     55                     ans++;
     56                 else
     57                 {
     58                     fx = find(a);
     59                     fy = find(b);
     60                     if (fx != fy)
     61                     {
     62                         fa[fy] = fx;
     63                         id[fy] = ((3 - id[b])%3 + (d - 1) + id[a]) % 3;
     64                     }
     65                     else
     66                     {
     67                         if ((3-id[a]+id[b])%3 != 0)
     68                             ans++;
     69 
     70                     }
     71                 }
     72             }
     73             else
     74             {
     75                 if (a > n || b > n)
     76                     ans++;
     77                 else
     78                 if (a == b)
     79                     ans++;
     80                 else
     81                 {
     82                     fx = find(a);
     83                     fy = find(b);
     84                     if (fx != fy)
     85                     {
     86                         fa[fy] = fx;
     87                         id[fy] = ((3 - id[b])%3  + (d - 1) + id[a]) % 3;
     88                     }
     89                     else
     90                     {
     91                         if ((3 - id[a] + id[b])%3 != 1)
     92                             ans++;
     93                     }
     94                 }
     95             }
     96         }
     97         printf("%d
    ", ans);
     98     }
     99     return 0;
    100 }
    View Code

     

    hdu3038

    有连续的一段数,数字是什么谁都不知道,  但是呢有限制条件。

    ai bi c 表示  下标ai到bi的这一段数的和为c

    现在给我们m个限制条件,问我们有多少个限制条件与前面的条件矛盾

    分析:依旧考察关系的传递, 只不过关系需要转换。  即 sum[bi] - sum[ai-1] = c

    然后ai-1作为父亲,  bi作为儿子, 权值为两者的差值。

    其余的都和食物链那题差不多了。

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <stdlib.h>
     4 #include <algorithm>
     5 #include <iostream>
     6 #include <queue>
     7 #include <stack>
     8 #include <vector>
     9 #include <map>
    10 #include <set>
    11 #include <string>
    12 #include <math.h>
    13 using namespace std;
    14 #pragma warning(disable:4996)
    15 #pragma comment(linker, "/STACK:1024000000,1024000000")
    16 typedef long long LL;                   
    17 const int INF = 1<<30;
    18 /*
    19 给定一些约束条件, 问有多少个错误的
    20 */
    21 const int N = 200000 + 10;
    22 int fa[N], r[N];
    23 int find(int x)
    24 {
    25     if (x == fa[x])return x;
    26     int f = fa[x];
    27     fa[x] = find(fa[x]);
    28     r[x] = r[x] + r[f];
    29     return fa[x];
    30 }
    31 int main()
    32 {
    33     int n, m;
    34     int a, b, fx, fy,w;
    35     while (scanf("%d%d", &n, &m) != EOF)
    36     {
    37         for (int i = 0; i <= n; ++i)
    38         {
    39             fa[i] = i;
    40             r[i] = 0;
    41         }
    42         int ans = 0;
    43         while (m--)
    44         {
    45             scanf("%d%d%d", &a, &b,&w);
    46             a--;
    47             fx = find(a);
    48             fy = find(b);
    49             if (fx != fy)
    50             {
    51                 fa[fy] = fx;
    52                 r[fy] = w + r[a] - r[b];
    53             }
    54             else if (r[b] - r[a] != w)
    55                 ans++;
    56         }
    57         printf("%d
    ", ans);
    58     }
    59     return 0;
    60 }
    View Code

    poj1733

    有长度为n的01序列,  有m个限制条件

    ai bi  even/odd   表示从ai到bi, 1的个数为偶数/奇数

    限制条件有可能相互矛盾,  题目要我们求出从哪里开始出现矛盾

    和上面那题一条的,  cnt[bi] - cnt[ai-1]  表示从ai到bi的1的个数

    然后ai-1作为父亲, bi作为儿子, 如果两者相减是偶数, 那么权值为0,如果是奇数, 权值为1.

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <stdlib.h>
     4 #include <algorithm>
     5 #include <iostream>
     6 #include <queue>
     7 #include <stack>
     8 #include <vector>
     9 #include <map>
    10 #include <set>
    11 #include <string>
    12 #include <math.h>
    13 #pragma warning(disable:4996)
    14 #pragma comment(linker, "/STACK:1024000000,1024000000")
    15 typedef long long LL;
    16 const int INF = 1 << 30;
    17 /*
    18 
    19 */
    20 std::map<int, int> ma;
    21 const int N = 20000 + 10;
    22 int fa[N], rank[N];
    23 int find(int x)
    24 {
    25     if (x == fa[x])
    26         return x;
    27     int f = fa[x];
    28     fa[x] = find(fa[x]);
    29     rank[x] = (rank[x] + rank[f]) % 2;
    30     return fa[x];
    31 }
    32 int main()
    33 {
    34     int n, m;
    35     int a, b, fx, fy, d;
    36     char str[11];
    37     scanf("%d%d", &n, &m);
    38     for (int i = 0; i < N; ++i)
    39     {
    40         fa[i] = i;
    41         rank[i] = 0;
    42     }
    43     int cnt = 0;
    44     int i;
    45     for (i = 0; i < m; ++i)
    46     {
    47         scanf("%d%d%s", &a, &b, str);
    48         a--;
    49         if (ma[a] == 0)
    50             ma[a] = ++cnt;
    51         a = ma[a];
    52         if (ma[b] == 0)
    53             ma[b] = ++cnt;
    54         b = ma[b];
    55         if (str[0] == 'o')
    56             d = 1;
    57         else
    58             d = 0;
    59         fx = find(a);
    60         fy = find(b);
    61         if (fx != fy)
    62         {
    63             fa[fx] = fy;
    64             rank[fx] = (rank[a] + rank[b] + d) % 2;
    65         }
    66         else if ((rank[a] + rank[b]) % 2 != d)
    67             break;
    68     }
    69     printf("%d
    ", i);
    70     return 0;
    71 }
    View Code

    poj1984

    n个点, m行条件,  每行 F1 F2 L E/W/N/S 表示F2在F1的E/W/N/S方向, 且距离为L

    然后有q个询问,每个询问F1 F2 i  表示在已知前i个条件的情况下,求F1和F2的笛卡尔距离。如果无法得到输出-1

    分析:其实也是维护元素与元素之间的关系, 只不过关系是他们的笛卡尔距离, 同样的, 这种关系同样具有传递性

      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <stdlib.h>
      4 #include <algorithm>
      5 #include <iostream>
      6 #include <queue>
      7 #include <stack>
      8 #include <vector>
      9 #include <map>
     10 #include <set>
     11 #include <string>
     12 #include <math.h>
     13 using namespace std;
     14 #pragma warning(disable:4996)
     15 #pragma comment(linker, "/STACK:1024000000,1024000000")
     16 typedef long long LL;                   
     17 const int INF = 1<<30;
     18 /*
     19 这次用并查集来维护的依旧是元素与元素之间的关系, 只不过关系是笛卡尔距离
     20 */
     21 const int N = 40000 + 10;
     22 int fa[N], rx[N], ry[N];
     23 int F1[N], F2[N], L[N], D[N];
     24 int find(int x)
     25 {
     26     if (x == fa[x]) return x;
     27     int f = fa[x];
     28     fa[x] = find(fa[x]);
     29     rx[x] = (rx[x] + rx[f]);
     30     ry[x] = (ry[x] + ry[f]);
     31     return fa[x];
     32 }
     33 
     34 int main()
     35 {
     36     int n, m, q;
     37     char str[3];
     38     int x, y, k, fx, fy;
     39     int i;
     40     while (scanf("%d%d", &n, &m) != EOF)
     41     {
     42         for ( i = 1; i <= n; ++i)
     43         {
     44             fa[i] = i;
     45             rx[i] = ry[i] = 0;
     46         }
     47         for ( i = 1; i <= m; ++i)
     48         {
     49             //E 用0表示
     50             scanf("%d%d%d%s", &F1[i], &F2[i], &L[i], str);
     51             if (str[0] == 'W')
     52             {
     53                 swap(F1[i], F2[i]);
     54                 D[i] = 0;
     55             }
     56             else if (str[0] == 'E')
     57                 D[i] = 0;
     58             else if (str[0] == 'N')
     59             {
     60                 swap(F1[i], F2[i]);
     61                 D[i] = 1;
     62             }
     63             else
     64                 D[i] = 1;
     65         }
     66         scanf("%d", &q);
     67         i = 1;
     68         while (q--)
     69         {
     70             scanf("%d%d%d", &x, &y, &k);
     71             for (; i <= k; ++i)
     72             {
     73                 fx = find(F1[i]);
     74                 fy = find(F2[i]);
     75                 if (fx != fy)
     76                 {
     77                     fa[fy] = fx;
     78                     if (D[i] == 0)
     79                     {
     80                         //L[i] - rx[F2[i]] 得到fy与F1[i]的相对距离
     81                         //再加上F1[i]与fx的相对距离,得到了 fy与fx的相对距离
     82                         rx[fy] = rx[F1[i]] + L[i] - rx[F2[i]];
     83                         ry[fy] = ry[F1[i]] + 0 - ry[F2[i]];
     84                     }
     85                     else
     86                     {
     87                         rx[fy] = rx[F1[i]] + 0 - rx[F2[i]];
     88                         ry[fy] = ry[F1[i]] + L[i] - ry[F2[i]];
     89                     }
     90                 }
     91             }
     92             fx = find(x);
     93             fy = find(y);
     94             if (fx != fy)
     95                 puts("-1");
     96             else
     97             {
     98                 int ans = abs((rx[y] - rx[fy]) - (rx[x] - rx[fx])) + abs((ry[y] - ry[fy]) - (ry[x] - ry[fx]));
     99                 printf("%d
    ", ans);
    100             }
    101         }
    102 
    103     }
    104     return 0;
    105 }
    View Code

    逆向并查集,离线存储后,逆向过来建并查集

    zoj3261

    给定n个星球, 每个星球有能量值pi,
    给定m条边, 表示
    然后有两种操作  query a     找到与a连通的能力最大的星球(这个星球的能力要比a大),如果有多个最大的,那么输出编号最小的

    destory a b 摧毁a和b之间的道路

    并查集要删边很困难,但是我们可以逆向来建并查集。且维护一个集合的父亲为这个集合中权值最大的元素,如果权值相同则设编号小的为父亲

      1 #include <stdio.h>
      2 #include <string.h>
      3 #include <stdlib.h>
      4 #include <algorithm>
      5 #include <iostream>
      6 #include <queue>
      7 #include <stack>
      8 #include <vector>
      9 #include <map>
     10 #include <set>
     11 #include <string>
     12 #include <math.h>
     13 #include <unordered_map>
     14 #include <unordered_map>
     15 using namespace std;
     16 #pragma warning(disable:4996)
     17 #pragma comment(linker, "/STACK:1024000000,1024000000")
     18 typedef long long LL;                   
     19 const int INF = 1<<30;
     20 /*
     21 给定n个星球, 每个星球有能量值pi,
     22 给定m条边, 表示
     23 然后有两种操作  query a     找到与a连通的能力最大的星球(这个星球的能力要比a大),如果有多个最大的,那么输出编号最小的
     24 
     25 
     26 
     27 找到连通的??? 
     28 set<pair<int,int> >;
     29 
     30 lower_bound(
     31 */
     32 const int N = 10000 + 1;
     33 int val[N];
     34 int fa[N];
     35 int u[N * 2], v[N * 2];
     36 int a[N * 5], b[N * 5], ans[N * 5];
     37 unordered_map<int, int> ma[N];//要开一个数组,
     38 int find(int x)
     39 {
     40     if (fa[x] == x)
     41         return x;
     42     return fa[x] = find(fa[x]);
     43 }
     44 void unionSet(int x, int y)
     45 {
     46     int fx = find(x);
     47     int fy = find(y);
     48     if (fx != fy)
     49     {
     50         if (val[fx] > val[fy])
     51             fa[fy] = fx;
     52         else if (val[fx] < val[fy])
     53             fa[fx] = fy;
     54         else
     55         {
     56             if (fx < fy)
     57                 fa[fy] = fx;
     58             else
     59                 fa[fx] = fy;
     60         }
     61     }
     62 }
     63 void input(int &x)
     64 {
     65     char ch = getchar();
     66     while (ch<'0' || ch>'9')
     67         ch = getchar();
     68     x = 0;
     69     while (ch >= '0' &&ch <= '9')
     70     {
     71         x = x * 10 + ch - '0';
     72         ch = getchar();
     73     }
     74 }
     75 int main()
     76 {
     77     int n, q, m;
     78     char query[10];
     79     int t = 1;
     80     while (scanf("%d", &n) != EOF)
     81     {
     82         if (t != 1)
     83             puts("");
     84         t++;
     85         
     86         for (int i = 0; i < n; ++i)
     87         {
     88             ma[i].clear();
     89             input(val[i]);
     90             fa[i] = i;
     91         }
     92         input(m);
     93         for (int i = 0; i < m; ++i)
     94         {
     95             //scanf("%d%d", &u[i], &v[i]);
     96             input(u[i]);
     97             input(v[i]);
     98             if (u[i] > v[i])
     99                 swap(u[i], v[i]);
    100         }
    101         input(q);
    102         for (int i = 0; i < q; ++i)
    103         {
    104             scanf("%s", query);
    105             if (query[0] == 'q')
    106             {
    107                 a[i] = -1;
    108                 input(b[i]);
    109             }
    110             else
    111             {
    112                 input(a[i]);
    113                 input(b[i]);
    114                 if (a[i] > b[i])
    115                     swap(a[i], b[i]);
    116                 ma[a[i]][b[i]] = 1;
    117             }
    118         }
    119         for (int i = 0; i < m; ++i)
    120         {
    121             if (ma[u[i]][v[i]]!=1)
    122                 unionSet(u[i], v[i]);
    123         }
    124         for (int i = q - 1; i >= 0; --i)
    125         {
    126             if (a[i] == -1)
    127             {
    128                 int fx = find(b[i]);
    129                 if (val[fx] > val[b[i]])
    130                     ans[i] = fx;
    131                 else
    132                     ans[i] = -1;
    133             }
    134             else
    135             {
    136                 ans[i] = -10;
    137                 unionSet(a[i], b[i]);
    138             }
    139         }
    140         for (int i = 0; i < q; ++i)
    141         if (ans[i] != -10)
    142             printf("%d
    ", ans[i]);
    143     }
    144     return 0;
    145 }
    View Code
  • 相关阅读:
    HOWTO: IE8下处理iframe自适应高度
    脚印:记录一次重构,将规则生产和规则消费(执行委托)分离
    Microsoft ASP.NET 2.0 AJAX 相关信息备忘
    脚印:软件开发随想录
    脚印:关于扩展方法的使用
    MVC 模式在javascript中的应用
    2007年总结
    下拉框自动回发!
    国庆前生活学习计划
    看完色戒有感
  • 原文地址:https://www.cnblogs.com/justPassBy/p/4693071.html
Copyright © 2020-2023  润新知