HDU2473 - Junk-Mail Filter: http://acm.hdu.edu.cn/showproblem.php?pid=2473
题目大意: M a b,代表a和b是同一类的,S a,代表原先给出的a的信息是错的,现在将其单独分成一类. 求最后一共有多少类邮件.
若只是分类,很直接就会想到并查集.但这里若直接用并查集是会出错的,因为删除的那个节点后面还可能会有其他的子节点,若直接把其删除,结果会出错. 这里就需要用到一个虚拟数组Trick,和Father数组合作,实现"删除"的目的(实际上该节点还是存在的).
代码:
#include <iostream> #include <cstring> #include <cstdio> using namespace std; const int MAXN = 1000111*2; int N,M; int x,y; int cnt,Case = 0,Ans; int Trick[MAXN],Father[MAXN],Hash[MAXN]; void Initial() { cnt = N; Ans = 0; for(int i = 0;i < MAXN;i++)//另开一个虚拟数组Trick,开始和Father储存一样的信息 Father[i] = Trick[i] = i,Hash[i] = 0; } int Find(int x) { if(x == Father[x])return x; return Father[x] = Find(Father[x]); } void Union(int x,int y) { x = Find(x); y = Find(y); if(x != y) Father[y] = x; } void Delete(int x) { Father[cnt] = cnt;//传进来的是Trick的信息,这里改变并不会影响x的子节点的查询 Trick[x] = cnt++;//更新后的信息在Trick里面,删除了x,表示x单独成为一个集合 } char op[5]; int main() { while(~scanf("%d%d",&N,&M),N + M) { Initial(); while(M--) { scanf("%s",op); if(op[0] == 'M') { scanf("%d%d",&x,&y); Union(Trick[x],Trick[y]);//传进去的是Trick里的信息,但查找合并的时候用的是Father,信息还是储存在Trick里,没有被破坏 }else{ scanf("%d",&x); Delete(x);//删除x节点 } } for(int i = 0;i < N;i++)//只有N个人是不会变的,查找一共被分成了几个集合 { x = Find(Trick[i]); if(!Hash[x])Hash[x] = 1,Ans++; } printf("Case #%d: %d\n",++Case,Ans); } return 0; }
版权声明:本文为博主原创文章,未经博主允许不得转载。
HDU2473 - Junk-Mail Filter 利用虚拟数组实现删除并查集的节点
原文地址:http://blog.csdn.net/p_rogrammer/article/details/48009427