码迷,mamicode.com
首页 > 其他好文 > 详细

UVA 11987 Almost Union-Find(并查集之五)

时间:2015-11-07 20:28:45      阅读:373      评论:0      收藏:0      [点我收藏+]

标签:

问题描述:

 

第一行为两个整数:n和m分别代表开始集合的个数和命令的个数。

初始化每个集合只有一个元素,从1到n一共n个集合,第i个集合里面的那一个元素值为i。

有三个命令:1命令后面紧跟两个参数p,q代表把p和q所在集合合并。

2命令同样两个参数,假设p,q代表把p单独从自己集合中拿出放到q集合里面。

1命令如果p,q已经在同一个集合里面,则忽略此命令,2命令同理。

3命令为查询命令,后面紧跟一个参数p,查询p所在集合中元素的个数和所有元素之和。

 

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

 

代码思路:

这道题因为n和m的最大值都为1e5且时间限制为1s,所以套两层大循环会TLE。

这道题会用到一个小技巧:

当2命令时,对根节点进行移动,如果对每一个子节点都进行遍历修改值得话会超时。这个时候,我们大可以不去动他,让他仍然去存储当前集合的信息,

而是用一个n之外的节点去代替它进行移动。当对此节点进行查询的时候可以去查找那个节点(因为如果这个点被移动了之后,就不可能再次成为根节点,所以d[]的值不会改变太多次),所以我们需要一个数组去存储下角标所对应的那个节点(替罪羊)在哪里,代码里面我是用的d[]。

 

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAX 100000
int n,m;
int pre[2*MAX+7],d[MAX+7],sum[MAX+7],num[MAX+7];
void init()
{
    for(int i=1;i<=MAX;i++)
    {
        pre[i]=i;
        sum[i]=i;
        num[i]=1;
        d[i]=i;
    }
}
int find(int x)
{
    int r=x;
    while(r!=pre[r])
        r=pre[r];
    int i=x,j;
    while(i!=r)
    {
        j=pre[i];
        pre[i]=r;
        i=j;
    }
    return r;
}
void mix(int x,int y,int opera)
{
    int fx=find(d[x]);
    int fy=find(d[y]);
    if(fx!=fy)
    {
        if(opera==1)
        {
            num[fy]+=num[fx];
            sum[fy]+=sum[fx];
            num[fx]=0;
            sum[fx]=0;
            pre[fx]=fy;
        }
        else
        {
            num[fx]--;
            sum[fx]-=x;
            num[fy]++;
            sum[fy]+=x;
            d[x]=x+MAX;
            pre[d[x]]=fy;
        }
    }
}
int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        init();
        for(int i=1;i<=m;i++)
        {
            int opera;
            scanf("%d",&opera);
            if(opera==1||opera==2)
            {
                int x,y;
                scanf("%d%d",&x,&y);
                mix(x,y,opera);
            }
            else
            {
                int x;
                scanf("%d",&x);
                int root=find(d[x]);
                printf("%d %d\n",num[root],sum[root]);
            }
        }
    }
    return 0;
}

 

UVA 11987 Almost Union-Find(并查集之五)

标签:

原文地址:http://www.cnblogs.com/burning-flame/p/4945943.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!