您的位置:首页 > 其它

Give you a Set

2015-07-17 11:19 411 查看
Give you a Set

Description

给你n个初始集合:{1}, {2}, {3}, …, {n}.,即每个集合中只有1个元素,第i(1<=i<=n)个集合中含有元素i。现在我们要对这n个集合做一些有趣的操作:

操作1:1 p q

解释: 合并 p 元素与q元素所在集合,如果p与q已经在一个相同的集合中了,忽略这个操作

操作 2:2 p q

解释 :把元素 p 移动到 元素 q 所在集合,如果p与q已经在一个相同的集合中了,忽略这个操作

操作 3: 3 p

解释 :返回包含元素p的集合的元素个数与该集合元素的总和

Input

输入有许多测试用例,每个测试用例第一行为n与m( 1 <=n,m<=100000 ),分别代表初始集合的总数,与 操作总数。以下m行为m个操作,保证操作合法,即1<=p,q<=n。输入到文件尾。输入文件大小不超过 5 M。

Output

对于每个操作3,输出两个整数:该集合元素的个数 与 集合中元素的总和。

Sample Input

5 7

1 1 2

2 3 4

1 3 5

3 4

2 4 1

3 4

3 3

Sample Output

3 12

3 7

2 8

Hint

初始集合:{1}, {2}, {3}, {4}, {5}

操作 1 1 2 后 :{1,2}, {3}, {4}, {5}

操作 2 3 4 后 :{1,2}, {3,4}, {5}( 忽略空集合 )

操作 1 3 5 后 :{1,2}, {3,4,5}

操作 2 4 1 后 :{1,2,4}, {3,5}

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>

using namespace std;

#define N 200010
int father
,num
;
int sum
;
int n,m;

int find(int a)
{
int r=a;
while(father[r]!=r) r=father[r];
for(int l=a,t;l!=r;l=t)
{
t=father[l];
father[l]=r;
}
return r;
}

void merge(int a,int b)
{
int aa=find(a),bb=find(b);
if(aa==bb)  return ;
int m=min(aa,bb);
father[aa]=father[a]=m;father[bb]=father[b]=m;
sum[aa]+=sum[bb];sum[bb]=sum[aa];
num[aa]+=num[bb];num[bb]=num[aa];
}

void link(int a,int b)
{
int aa=find(a),bb=find(b);
if(aa==bb)  return ;
father[a]=bb;
num[aa]--,num[bb]++;
sum[aa]-=a,sum[bb]+=a;
}

void query(int a)
{
int aa=find(a);
printf("%d %d\n",num[aa],sum[aa]);
}
void init()
{
for(int i=1;i<=n;i++)
{
father[i]=n+i;
}
for(int i=n+1;i<=2*n;i++)
{
father[i]=i;
}
for(int i=n+1;i<=2*n;i++)
{
num[i]=1;
sum[i]=i-n;
}
}

int main()
{
//freopen("in.txt","r",stdin);
while(scanf("%d %d",&n,&m)!=EOF)
{
init();
int c,a,b;
while(m--)
{
scanf("%d",&c);
switch(c)
{
case 1:scanf("%d %d",&a,&b);merge(a,b);break;
case 2:scanf("%d %d",&a,&b);link(a,b);break;
case 3:scanf("%d",&a);query(a);break;
default:;
}
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: