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,受宠若惊……

浙公网安备 33010602011771号