UVa 11987:Almost Union-Find

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=18692

题目大意:

写一个支持查询集合元素个数和元素和的并查集,同时支持合并操作,把一个元素从一个集合拿到另一个集合的操作。

分析:

大意就是要写一个支持删除操作的并查集,元素个数和元素和什么的随便加权瞎搞。

想了一下支持删除的该怎么写:我们应该让任意元素结点之间没有祖先关系,所以:

我们给每个元素结点存一个虚拟父节点,权值存在这个父节点上,所以就不会有合并时把一个元素结点连接到另一个元素结点上了,删除时直接更改元素父节点

这里写图片描述

具体看代码咯:

代码:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cctype>

#define rep(i,x,y) for (int i=x;i<=y;i++)
#define dep(i,y,x) for (int i=y;i>=x;i--)

using namespace std;

const int maxn=400000+10;

typedef long long LL;

int F[maxn],num[maxn],n,m,k,x,y;

LL sum[maxn];

int readint()
{
 char c=getchar();
 while (!isdigit(c) && (c!='-')) c=getchar();
 
 int mark;

 if (c=='-') {mark=-1;c=getchar();} else mark=1;

 int x=0;

 while (isdigit(c))
 {
  x=x*10+(c-'0');
  c=getchar();
 }

 return x*mark;
}

void writeint(int x)
{
 int buf[30];

 if (x==0) 
  printf("0");
 else 
 {
  bool mark;
  if (x<0) {mark=1;x=-x;} else mark=0;
  int p=0;
  while (x)
  {
   buf[++p]=x%10;
   x/=10;
  }
  
  if (mark) putchar('-');

  dep(i,p,1)
    putchar('0'+buf[i]);
 }
 printf("\n");
}

void init() //初始化
{
 rep(i,1,n) 
 {
  F[i]=n+i; F[n+i]=n+i;
  sum[n+i]=i; num[n+i]=1;
 }
}

int find(int k) //查询
{
 if (F[k]==k)
  return k;
 else 
 {
  int p=find(F[k]);
  return F[k]=p;
 }
}

void unit(int x,int y) //合并
{
 int p=find(x),q=find(y);
 if (p==q) return;
 F[p]=q;
 num[q]+=num[p];
 sum[q]+=sum[p];
}

void trans(int x,int y) //移动
{
 int p=find(x),q=find(y);
 num[p]--;num[q]++;
 sum[p]-=x;sum[q]+=x;
 F[x]=q;
}

int main()
{
 while (scanf("%d%d",&n,&m)==2)
 {
  init();
  rep(i,1,m)
  {
   k=readint();
   if (k==1) {x=readint();y=readint();unit(x,y);}
   if (k==2) {x=readint();y=readint();trans(x,y);}
   if (k==3) {x=readint();printf("%d %lld\n",num[find(x)],sum[find(x)]);}
  }
 }
 return 0;
}

意外的刷了个rank1,受宠若惊……

posted @ 2016-06-12 23:40  Krew  阅读(177)  评论(0)    收藏  举报