• 并查集--CSUOJ 1601 War


    并查集的经典题目:

    CSUOJ 1601: War

    Time Limit: 1 Sec  Memory Limit: 128 MB
    Submit: 247  Solved: 70
    [Submit][Status][Web Board]

    Description

    AME decided to destroy CH’s country. In CH’ country, There are N villages, which are numbered from 1 to N. We say two village A and B are connected, if and only if there is a road between A and B, or there exists a village C such that there is a road between A and C, and C and B are connected. To defend the country from the attack of AME, CH has decided to build some roads between some villages. Let us say that two villages belong to the same garrison area if they are connected.
    Now AME has already worked out the overall plan including which road and in which order would be attacked and destroyed. CH wants to know the number of garrison areas in his country after each of AME’s attack.

    Input

    The first line contains two integers N and M — the number of villages and roads, (2 ≤ N ≤ 100000; 1 ≤ M ≤ 100000). Each of the next M lines contains two different integers u, v (1<=u, v<=N)—which means there is a road between u and v. The next line contains an integer Q which denotes the quantity of roads AME wants to destroy (1 ≤ Q ≤ M). The last line contains a series of numbers each of which denoting a road as its order of appearance — different integers separated by spaces.

    Output

    Output Q integers — the number of garrison areas in CH’s country after each of AME's attack. Each pair of numbers are separated by a single space.

    Sample Input

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

    Sample Output

    3
    1 2 3
     1 /*题目大意:n个点m条边(边1,边2...边m),q个要摧毁的边,求按顺序每摧毁一条边后图中连通块的个数
     2 
     3  
     4 
     5 题目分析:并查集,先找出最后状态,反向加边,先将q条路全部摧毁后的连通块个数求出来,然后加边即可,每加一条边,用并查集判断,若两点不在同一连通块中,则合并且连通块个数减1*/
     6 #include<cstdio>
     7 #include<cstring>
     8 #define N 100100
     9 struct Edge {
    10     int u,v;
    11 }edge[N];
    12 bool visited[N];
    13 int a[N],stack[N];
    14 int n,m,q,ans=0;
    15 int father[N];
    16 int find(int x)
    17 {
    18     return (father[x]==x)?father[x]:father[x]=find(father[x]);/*注意路径压缩和返回father[x]*/
    19 }
    20 void add_tu()
    21 {
    22     for(int i=1;i<=n;++i)
    23     father[i]=i;
    24     for(int i=1;i<=m;++i)
    25     {
    26         if(visited[i]) continue;
    27         int r1=find(edge[i].u);
    28         int r2=find(edge[i].v);
    29         if(r1!=r2)
    30         {
    31             father[r2]=r1;
    32             ans--;/*先把连通块的数目设为n,建图的过程中,边建边删除,也可以统计father[i]==i*/
    33         }
    34     }
    35     stack[q]=ans;/*当前的状态是q的状态,不能加边了*/
    36 }
    37 void add_edge()
    38 {
    39     for(int i=q-1;i>=1;--i)
    40     {
    41         int r1=find(edge[a[i+1]].u);/*注意加的这一条边是当前状态的后一条边,因为这个后一条边没有删除,而不是a[i],之前深受其害,连样例都过了*/
    42         int r2=find(edge[a[i+1]].v);
    43         if(r1!=r2)
    44         {
    45             father[r2]=r1;
    46             ans--;
    47             
    48         }
    49         stack[i]=ans;/*注意不要把这句放到if里面*/
    50     }
    51 }
    52 int main()
    53 {
    54     while(scanf("%d%d",&n,&m)!=EOF)/*注意这里不能只用scanf("%d%d",&n,&m),因为这样没法用^z结束程序*/
    55         memset(edge,0,sizeof(edge));
    56         memset(visited,false,sizeof(visited));/*别忘记初始化*/
    57         memset(a,0,sizeof(a));
    58         memset(stack,0,sizeof(stack));
    59         ans=n;
    60         for(int i=1;i<=m;++i)
    61         {
    62             scanf("%d%d",&edge[i].u,&edge[i].v);
    63         }
    64         scanf("%d",&q);
    65         for(int i=1;i<=q;++i)
    66         {
    67             scanf("%d",&a[i]);
    68             visited[a[i]]=true;/*把不访问的边设上标记*/
    69         }
    70         add_tu();
    71         add_edge();
    72         for(int i=1;i<=q-1;++i)
    73         printf("%d ",stack[i]);/*CSUOJ这个坑爹的OJ,多输出一个空格,就格式不对*/
    74         printf("%d
    ",stack[q]);
    75     }
    76     return 0;
    77 }
     
  • 相关阅读:
    组合总和
    子集Ⅱ
    子集
    全排列Ⅱ
    全排列
    填充下一个结点下一个Next结点
    把二叉树转化成累加树
    二叉树的左叶子之和
    高速C/C++编译工具ccache
    【转载】如何用U盘制作Ubuntu启动盘
  • 原文地址:https://www.cnblogs.com/c1299401227/p/5475918.html
Copyright © 2020-2023  润新知