• [bzoj1015][JSOI2008]星球大战——并查集+离线处理


    题解

    给定一张图,支持删点和询问连通块个数

    按操作顺序处理的话要在删除点的同时维护图的形态(即图具体的连边情况),这是几乎不可做的

    我们发现,这道题可以先读入操作,把没删的点的边先连上,然后再倒序处理操作

    这样的话从删点变成了加点,而且只要维护连通块的数量,用并查集可以快速的解决这个问题

    代码

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 4 * 200000;
    int n, m, q[maxn];
    vector<int> G[maxn];
    int fa[maxn], added[maxn], des[maxn], ans[maxn];
    int tot = 0;
    int find(int x) { return fa[x] = fa[x] == x ? x : find(fa[x]); }
    void add(int x) {
      int p = find(x), q;
      added[x] = 1;
      for (int i = 0; i < G[x].size(); i++) {
        if (added[G[x][i]]) {
          q = find(G[x][i]);
          if (p != q) {
            fa[q] = p;
            tot--;                //连通块少一个
          }
        }
      }
    }
    int main() {
      // freopen("input", "r", stdin);
      scanf("%d %d", &n, &m);
      for (int i = 1; i <= m; i++) {
        int x, y;
        scanf("%d %d", &x, &y);
        G[x].push_back(y);
        G[y].push_back(x);
      }
      memset(added, 0, sizeof(added));
      for (int i = 0; i < n; i++)
        fa[i] = i;
      int d;
      scanf("%d", &d);
      for (int i = 1; i <= d; i++) {
        scanf("%d", &q[i]);
        des[q[i]] = 1;
      }
      for (int i = 0; i < n; i++) {
        if (!des[i]) {
          tot++;
          add(i);
          added[i] = 1;
        }
      }
      ans[d + 1] = tot;
      for (int i = d; i > 0; i--) {
        tot++;                //连通块多一个
        add(q[i]);
        added[q[i]] = 1;
        ans[i] = tot;
      }
      for (int i = 1; i <= d + 1; i++)
        printf("%d
    ", ans[i]);
      return 0;
    }
    
  • 相关阅读:
    扫盲如何在ECLIPSE中使用条件断点
    春困
    气虚咳喘案
    知足老师论糖尿病
    辨痰之病位与寒热
    常用中药功效比较(任之堂)
    女子全身窜痛案
    小儿外感案
    紫斑案
    读任之堂中药讲记笔记
  • 原文地址:https://www.cnblogs.com/gengchen/p/6433863.html
Copyright © 2020-2023  润新知