合纵连横
时间限制:
1000 ms | 内存限制:
65535 KB
难度:
3
-
描述
-
乱世天下,诸侯割据。每个诸侯王都有一片自己的领土。但是不是所有的诸侯王都是安分守己的,实力强大的诸侯国会设法吞并那些实力弱的,让自己的领土面积不断扩大。而实力弱的诸侯王为了不让自己的领土被吞并,他会联合一些其他同样弱小的诸侯国,组成联盟(联盟不止一个),来共同抵抗那些强大的诸侯国。 强大的诸侯国为了瓦解这些联盟,派出了最优秀的间谍来离间他们,使一些诸侯国退出联盟。最开始,每个诸侯国是一个联盟。
有两种操作
1、U x y 表示x和y在同一个联盟。
(0 ≤ x,y<n )2、D x 表示x退出联盟。
-
输入
-
多组测试数据
第一行两个数,n和m(1 ≤ n≤ 10^5, 1 ≤ m ≤10^5),分别表示诸侯国的个数和操作次数。
接下来有m行操作
输出
- 输出联盟的个数 样例输入
-
5 7 U 0 1 U 1 2 U 0 3 D 0 U 1 4 D 2 U 0 2 10 1 U 0 9
样例输出
-
Case #1: 2 Case #2: 9
上传者
#include<stdio.h>
#include<string.h>
#define N 200010//注意数组一定要开到大一些
//因为在后期,删除原来合并的树中的元素时,par[]的数组下标要大于 n
int num[100010];//按题目要求大小就好,开大了,非时间
int par[N];
int vis[N];
void init(int n){
for(int i=0;i<n;i++)
{
par[i]=i;
num[i]=i;
}
}
int find(int x)
{
int r,j,k;
r=x;
while(r!=par[r])
r=par[r];
k=x;
while(k!=r)
{
j=par[k];
par[k]=r;
k=j;
}
return r;
}
bool unite(int x,int y)
{
int fx=find(x);
int fy=find(y);
if(fx!=fy)
par[fx]=fy;
}
int main()
{
int n,q;
int u,v;
char c;
int sum,t,tmp;
int kase=1;
while(~scanf("%d%d",&n,&q))
{
init(n);
sum=0;
t=n;
while(q--)
{
getchar();//不接受个字符,后面就没法输入
scanf("%c",&c);
if(c=='U')
{
scanf("%d%d",&u,&v);
unite(num[u],num[v]);
}
else{//并查集删除元素,其实就是装在根结点中的元素换了个位置,重新添加新的根结点给换位置的元素,之前老的根结点不动。
scanf("%d",&u);
num[u]=t;
par[t]=t;
t++;
}
}
memset(vis,0,sizeof(vis));
for(int i=0;i<n;i++)
{
tmp=find(num[i]);
if(vis[tmp]==0)
{
vis[tmp]=1;
sum++;
}
}
printf("Case #%d: %d\n",kase++,sum);
}
return 0;
}