foj2155 - 盟国 (并查集的删除操作)

来源:互联网 发布:淘宝直播账号出售 编辑:程序博客网 时间:2024/05/16 15:41

题目链接

思路

并查集的删除节点,基本的并查集只涉及合并和查询,没有删除。
并查集的结构是树形的,在删除一个节点的同时还要保持其子节点与根节点的相对关系,是很麻烦的,所以我们的做法就是不去删除,而是重新为它开辟空间来进行存储。
也就是再开一个info数组,来保存各个节点的关系的存储位置,在用一个par数组来维护节点之间的关系,由于大量的删除,所以info数组要远大于par数组。
对于整个代码来说,并查集的操作并不需要变化,只需要添加一个del函数。例如查询 i 的根节点时,需要调用info[i]。

代码

#include <cstring>#include <cstdio>#include <set>using namespace std;const int maxn = 100000;int info[maxn+10];int par[maxn*10];bool vis[maxn*10];int nCount;void init(int n){    for(int i=0; i<n; i++)    {        par[i] = info[i] = i;    }    nCount = n;}int get_par(int a){    if(par[a]==a) return a;    else return par[a] = get_par(par[a]);}void merge(int a, int b){    int pa = get_par(a);    int pb = get_par(b);    if(pa!=pb)        par[pb] = pa;}// 删除节点void del(int a){    // 额外分配空间    info[a] = nCount;    par[nCount] = nCount;    nCount++;}int main(){    int n, m, tt=1;    int a, b;    char op[5];    while(scanf("%d%d", &n, &m)&&n)    {        init(n);        for(int i=0; i<m; i++)        {            scanf("%s%d", op, &a);            if(op[0]=='M')            {                scanf("%d", &b);                merge(info[a], info[b]);            }            else            {                del(a);            }        }        memset(vis, false, sizeof(vis));        int re = 0;        for(int i=0; i<n; i++)        {            int temp = get_par(info[i]);            if(!vis[temp])            {                vis[temp] = true;                re++;            }        }        printf("Case #%d: %d\n", tt++, re);    }    return 0;}
0 0
原创粉丝点击