zoukankan      html  css  js  c++  java
  • 并查集的用法——维护图的连通性

    luogu P1197 [JSOI2008]星球大战

    题目大意
    给出N个星球之间的M个
    连接关系,按顺序摧毁k个
    星球,问每次摧毁后图中有
    多少个连通块。


    数据范围
    1<=M<=200,000
    1<=k<=N<=2M

     1 /*思想: 反向恢复星球, 用并查集维护关系*/ 
     2 #include<cstdio>
     3 using namespace std;
     4 #define MAX 400000+99
     5 #define MAXN 800000+99//不用在意范围,博主为了赶时间AC,没算
     6 
     7 int fa[MAX];
     8 int n,m,k,tot;
     9 int cmd[MAX],ans[MAX],vis[MAXN];
    10 int head[MAXN], cnt;
    11 struct edge{
    12     int x,y;
    13     int next;
    14 }e[MAX];
    15 
    16 void add_edge(int x, int y) {
    17     e[++cnt].x = x;
    18     e[cnt].y = y;
    19     e[cnt].next = head[x];
    20     head[x] = cnt; 
    21 }
    22 
    23 int find(int x) {
    24     if(fa[x] == x) return fa[x];
    25     else return fa[x] = find(fa[x]);
    26 }
    27 
    28 int main() {
    29     scanf("%d%d",&n,&m);
    30     for(int i = 0; i < n; i++) fa[i] = i;
    31     int x,y,fax, fay;
    32     for(int i = 1; i <= m; i++){
    33         scanf("%d %d", &x, &y);
    34         add_edge(x,y);
    35         add_edge(y,x);
    36     } 
    37     scanf("%d", &k);
    38     tot = n - k;//打击完后还剩的点 
    39     for(int i = 1; i <= k; i++) scanf("%d", &cmd[i]), vis[ cmd[i] ] = 1;
    40     //记录并保存摧毁目标 (将他们每个都看成个联通快 
    41     for(int i = 1; i <= m*2; i++) {//合并没有打击到的 
    42         x = e[i].x , y = e[i].y ;
    43         fax = find(x), fay = find(y);
    44         if(!vis[x] && !vis[y])//如果都没打击到(体现倒推 
    45             if(fax != fay) {//并且没有连接过 
    46                 fa[fax] = fay;
    47                 tot--;//将他们连接 ,联通快-- 
    48             } 
    49     }
    50     ans[k+1] = tot;//此处为k次打击完了之后的ans 
    51     for(int j = k; j >= 1; j--) { // 我们的思想 
    52         x = cmd[j]; 
    53         vis[x] = 0;//恢复这个星球(倒推 
    54         tot++;//因为恢复了,所以多了一个点 
    55         for(int i = head[x]; i; i = e[i].next ) {//遍历与这个恢复星球相连的星球 
    56             y = e[i].y ;
    57             fax = find(x), fay = find(y);
    58             if(!vis[y] && fax != fay) {// 如果y没有被打击,而且没有相连过(即在另一个联通快 
    59                 tot--;//合并 
    60                 fa[fax] = fay;//注意尽量不要到过来赋值,这样会不断改变father 
    61             }
    62         }
    63         ans[j] = tot;
    64     }
    65 
    66     for(int i = 1; i <= k+1; i++) printf("%d ", ans[i]);
    67     return 0;
    68 }
  • 相关阅读:
    利用拦截器与自定义注解实现未登录拦截
    消息中间件activeMQ
    linux中redis的安装配置,后门漏洞修复及其攻击方法整合
    hibernate二级缓存
    初级程序员实战面试宝典(二)
    spring定时任务之-quartz调度器
    【微信小程序推广营销】教你微信小程序SEO优化,让你的小程序快人一步抢占先机
    ajax——CORS跨域调用REST API 的常见问题以及前后端的设置
    后台管理UI的选择
    微信小程序如何引入外部字体库iconfont的图标
  • 原文地址:https://www.cnblogs.com/tyner/p/10932110.html
Copyright © 2011-2022 走看看