zoukankan      html  css  js  c++  java
  • P1197 星球大战(并查集+链式向前星)

     1 #include<iostream>
     2 using namespace std;
     3 const int N=4e5+100;
     4 struct edge
     5 {
     6     int from;
     7     int to;
     8     int nex;
     9 };
    10 edge a[N];
    11 int head[N];
    12 int cnt=0;
    13 //以上是链式向前星存储图
    14 int fa[N];//并查集
    15 bool used[N];//每个点是否被摧毁
    16 int node[N];//被摧毁的
    17 int ans[N];//答案
    18 void init(int n)
    19 {
    20     for(int i=0;i<n;i++)
    21     {
    22         fa[i]=i;//并查集
    23         used[i]=0;
    24         head[i]=-1;
    25     }
    26 }
    27 void add(int b,int c)//边的计数从0开始
    28 {
    29     a[cnt].from=b;
    30     a[cnt].to=c;
    31     a[cnt].nex=head[b];
    32     head[b]=cnt;
    33     cnt++;
    34 }
    35 int finds(int x)
    36 {
    37     while(fa[x]!=fa[fa[x]])
    38     {
    39         fa[x]=fa[fa[x]];
    40     }
    41     return fa[x];
    42 }
    43 int main(void)
    44 {
    45     int n,m;
    46     cin>>n>>m;
    47     init(n);//初始化
    48     for(int i=1;i<=m;i++)
    49     {
    50         int a,b;
    51         cin>>a>>b;
    52         add(a,b);//无向图
    53         add(b,a);
    54     }
    55     int k;
    56     cin>>k;
    57     for(int i=0;i<k;i++)//被摧毁的顺序,反过来就是重建的顺序
    58     {
    59         cin>>node[i];
    60         used[node[i]]=1;//标记为已打击
    61     }
    62     int total=n-k;//假设全部的边都不存在,那么所有打击完成之后,所剩的联通分量就是n-k
    63                     //以下计算打击完成后的连通分量数
    64     for(int i=0;i<2*m;i++)//遍历所有的边
    65     {
    66         if(used[a[i].from]==0&&used[a[i].to]==0)//如果都没有被打击
    67         {
    68             if(finds(a[i].from)!=finds(a[i].to))//且在此前没有被连接在一起
    69             {
    70                 total--;
    71                 fa[finds(a[i].from)]=finds(a[i].to);
    72             }
    73         }
    74     }
    75     ans[k]=total;
    76     for(int i=k-1;i>=0;i--)
    77     {
    78         int t=node[i];
    79         total++;
    80         used[t]=0;//已修复,没有被打击
    81         for(int i=head[t];i!=-1;i=a[i].nex)//遍历修复的点的全部边
    82         {
    83             if(used[a[i].to]==0&&finds(t)!=finds(a[i].to))//如果可以连而且还没连
    84             {
    85                 total--;
    86                 fa[finds(t)]=finds(a[i].to);
    87             }
    88         }
    89         ans[i]=total;
    90     }
    91     for(int i=0;i<=k;i++)
    92     {
    93         cout<<ans[i]<<endl;
    94     }
    95     return 0;
    96 }

    让你确定每次打击之后还有多少个联通分量(并查集似乎顺着做不了),就只有逆着来做了

    首先假设所有将要打击的点都被破坏,然后再一步一步重建,这就是正常的并查集了,但是链式向前星挺难的

  • 相关阅读:
    Codeforces Round #350 (Div. 2) F. Restore a Number 模拟
    Codeforces Round #374 (Div. 2) C. Journey DP
    Codeforces Round #375 (Div. 2) D. Lakes in Berland DFS
    Intel Code Challenge Elimination Round (Div.1 + Div.2, combined) D. Generating Sets 堆
    Ubuntu 安装 搜狗输入法
    Ubuntu 搜索不到WIFI或连接不上的解决方法
    Ubuntu 线缆被拔出问题
    Codeforces Round #357 (Div. 2) D. Gifts by the List DFS
    Codeforces Round #357 (Div. 2) C. Heap Operations 优先队列
    Codeforces Round #356 (Div. 2) C. Bear and Prime 100 交互题
  • 原文地址:https://www.cnblogs.com/greenofyu/p/12256086.html
Copyright © 2011-2022 走看看