zoukankan      html  css  js  c++  java
  • BZOJ 3237: [Ahoi2013]连通图

    3237: [Ahoi2013]连通图

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 1161  Solved: 399
    [Submit][Status][Discuss]

    Description

    Input

    Output

    Sample Input

    4 5
    1 2
    2 3
    3 4
    4 1
    2 4
    3
    1 5
    2 2 3
    2 1 2

    Sample Output



    Connected
    Disconnected
    Connected

    HINT


    N<=100000 M<=200000 K<=100000

    Source

     
    [Submit][Status][Discuss]

    很有意思的一道题。乍一看就是LCT,后来听说可以CDQ水过,一想确实哎,写写就1A了。

    对于一张图的连通性,我们可以用并查集维护,简单方便,可是不支持删边操作(这里指的是随机的删边)。但发现可以通过记录father数组的更改,得到一个回溯栈,方便地进行顺序删边。

    利用CDQ分治的想法,在一个solve(l,r)时,考虑把(mid,r]内的边补回到图中,维护并查集并记录改变(用来回溯),然后递归solve(l,mid),最后回溯;再把[l,mid]的边补回,递归右侧,回溯。这样到底层solve(l,r),即l==r时,并查集维护的刚好不包含当前这组询问中的边,此时记录下答案即可。

      1 #include <bits/stdc++.h>
      2 
      3 inline int getC(void) {
      4     static const int siz = 1024;
      5     
      6     static char buf[siz];
      7     static char *hd = buf + siz;
      8     static char *tl = buf + siz;
      9     
     10     if (hd == tl)
     11         fread(hd = buf, 1, siz, stdin);
     12     
     13     return int(*hd++);
     14 }
     15 
     16 inline int getI(void) {
     17     register int ret = 0;
     18     register int neg = false;
     19     register int bit = getC();
     20     
     21     for (; bit < 48; bit = getC())
     22         if (bit == '-')neg ^= true;
     23 
     24     for (; bit > 47; bit = getC())
     25         ret = ret * 10 + bit - '0';
     26     
     27     return neg ? -ret : ret;
     28 }
     29 
     30 const int maxn = 500005;
     31 
     32 int n, m, p;
     33 
     34 struct edge {
     35     int x, y; 
     36 }e[maxn];
     37 
     38 struct query {
     39     int k, s[5];
     40     bool connect;
     41 }q[maxn];
     42 
     43 int fa[maxn];
     44 int sz[maxn];
     45 
     46 int cnt[maxn];
     47 
     48 inline int find(int u) {
     49     while (fa[u] != u)
     50         u = fa[u];
     51     return u;
     52 }
     53 
     54 int stk[maxn], tot;
     55 
     56 void solve(int l, int r) {
     57     if (l == r) {
     58         q[l].connect = sz[find(1)] == n;
     59         return;
     60     }
     61     
     62     int mid = (l + r) >> 1, top = tot;
     63     
     64     for (int i = l; i <= mid; ++i)
     65         for (int j = 1; j <= q[i].k; ++j)
     66             if (--cnt[q[i].s[j]] == 0) {
     67                 int x = find(e[q[i].s[j]].x);
     68                 int y = find(e[q[i].s[j]].y);
     69                 if (x != y) {
     70                     if (sz[x] < sz[y])
     71                         fa[x] = y, sz[y] += sz[x], stk[++tot] = x;
     72                     else
     73                         fa[y] = x, sz[x] += sz[y], stk[++tot] = y;
     74                 }
     75             }
     76     
     77     solve(mid + 1, r);
     78     
     79     while (tot > top) {
     80         int t = stk[tot--];
     81         sz[fa[t]] -= sz[t];
     82         fa[t] = t;
     83     }
     84     
     85     for (int i = l; i <= mid; ++i)
     86         for (int j = 1; j <= q[i].k; ++j)
     87             ++cnt[q[i].s[j]];
     88     
     89     for (int i = mid + 1; i <= r; ++i)
     90         for (int j = 1; j <= q[i].k; ++j)
     91             if (--cnt[q[i].s[j]] == 0) {
     92                 int x = find(e[q[i].s[j]].x);
     93                 int y = find(e[q[i].s[j]].y);
     94                 if (x != y) {
     95                     if (sz[x] < sz[y])
     96                         fa[x] = y, sz[y] += sz[x], stk[++tot] = x;
     97                     else
     98                         fa[y] = x, sz[x] += sz[y], stk[++tot] = y;
     99                 }
    100             }
    101     
    102     solve(l, mid);
    103     
    104     while (tot > top) {
    105         int t = stk[tot--];
    106         sz[fa[t]] -= sz[t];
    107         fa[t] = t;
    108     }
    109     
    110     for (int i = mid + 1; i <= r; ++i)
    111         for (int j = 1; j <= q[i].k; ++j)
    112             ++cnt[q[i].s[j]];
    113 }
    114 
    115 signed main(void) {
    116     n = getI();
    117     m = getI();
    118     
    119     for (int i = 1; i <= n; ++i)
    120         fa[i] = i, sz[i] = 1;
    121         
    122     for (int i = 1; i <= m; ++i)
    123         e[i].x = getI(),
    124         e[i].y = getI();
    125         
    126     p = getI();
    127     
    128     for (int i = 1; i <= p; ++i) {
    129         q[i].k = getI();
    130         for (int j = 1; j <= q[i].k; ++j)
    131             ++cnt[q[i].s[j] = getI()];
    132     }
    133     
    134     for (int i = 1; i <= m; ++i)
    135         if (!cnt[i]) {
    136             int x = find(e[i].x);
    137             int y = find(e[i].y);
    138             if (x != y) {
    139                 if (sz[x] < sz[y])
    140                     fa[x] = y, sz[y] += sz[x];
    141                 else
    142                     fa[y] = x, sz[x] += sz[y];
    143             }
    144         }
    145         
    146     solve(1, p);
    147     
    148     for (int i = 1; i <= p; ++i)
    149         puts(q[i].connect ? "Connected" : "Disconnected");
    150 }

    @Author: YouSiki

  • 相关阅读:
    前后端分类状态下SpringSecurity的玩法
    拓展 centos 7
    linux 日志管理
    Linux 内存监控
    Linux 周期任务
    Linux 文件系统
    linux 磁盘管理
    图论 最短路总结
    进阶线段树之乘法操作
    暑假集训Day 10 小烈送菜
  • 原文地址:https://www.cnblogs.com/yousiki/p/6243002.html
Copyright © 2011-2022 走看看