• [luoguP1197] [JSOI2008]星球大战(并查集)


    传送门

    思维!重要的是思维!

    题目让删边,然而并查集不好删边(并!查!集!啊)

    我们离线处理,从后往前添边,这样并查集就可以用了。

    用并查集维护连通块个数即可。

    ——代码

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <iostream>
     4 #define N 400001
     5 
     6 int n, m, k, ans, cnt;
     7 int head[N], to[N << 1], next[N << 1], f[N], a[N], anslist[N];
     8 bool vis[N];
     9 
    10 inline int read()
    11 {
    12     int x = 0, f = 1;
    13     char ch = getchar();
    14     for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
    15     for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
    16     return x * f;
    17 }
    18 
    19 inline void add(int x, int y)
    20 {
    21     to[cnt] = y;
    22     next[cnt] = head[x];
    23     head[x] = cnt++;
    24 }
    25 
    26 inline int find(int x)
    27 {
    28     return x == f[x] ? x : f[x] = find(f[x]);
    29 }
    30 
    31 int main()
    32 {
    33     int i, j, x, y, fx, fy;
    34     n = read();
    35     m = read();
    36     memset(head, -1, sizeof(head));
    37     for(i = 1; i <= m; i++)
    38     {
    39         x = read();
    40         y = read();
    41         add(x, y);
    42         add(y, x);
    43     }
    44     k = read();
    45     for(i = 1; i <= k; i++)
    46     {
    47         a[i] = read();
    48         vis[a[i]] = 1;
    49     }
    50     ans = n - k;
    51     for(i = 0; i < n; i++) f[i] = i;
    52     for(x = 0; x < n; x++)
    53     {
    54         if(vis[x]) continue;
    55         for(i = head[x]; i ^ -1; i = next[i])
    56         {
    57             y = to[i];
    58             if(vis[y]) continue;
    59             fx = find(x);
    60             fy = find(y);
    61             if(fx ^ fy) f[fx] = fy, ans--; 
    62         }
    63     }
    64     anslist[k] = ans;
    65     for(i = k; i >= 1; i--)
    66     {
    67         x = a[i];
    68         ans++;
    69         for(j = head[x]; j ^ -1; j = next[j])
    70         {
    71             y = to[j];
    72             if(vis[y]) continue;
    73             fx = find(x);
    74             fy = find(y);
    75             if(fx ^ fy) f[fx] = fy, ans--;
    76         }
    77         vis[x] = 0;
    78         anslist[i - 1] = ans;
    79     }
    80     for(i = 0; i <= k; i++) printf("%d
    ", anslist[i]);
    81     return 0;
    82 }
    View Code

    总结:有些需要删边询问连通性之类的题目,可以试试从后往前用并查集添边。

       逆向思维很重要!正着不方便就反着来。

  • 相关阅读:
    拯救公主
    爱情之路
    无聊的会议
    对拍检验程序
    TCP三次握手
    OA系统走过的的坑之部门岗位管理
    蓝屏警告
    三级联动
    Ajax二级联动
    近期疑惑和总结
  • 原文地址:https://www.cnblogs.com/zhenghaotian/p/7020003.html
Copyright © 2020-2023  润新知