题目链接
题目思路
其实看到合并就要想到并查集,但是自己还是不知道怎么写,其实也相当于是一个裸题,把sm数组和bi数组初始化为自己的值。
然后再更新是一样的操作,还有更新最大值和最小值的情况只要更新祖宗节点就可以,不要全部跟新,要不然就出锅(我就wawawa了
还有题目有一个找最小编号的操作,其实完全没有必要用一个数组,直接联合的时候让自己父亲节点的值小就好。
还有合并的时候一定注意是祖宗节点合并,wa过很多次了
代码
#include<algorithm>
#include<cstdio>
using namespace std;
const int maxn=1e5+5;
int n,m,k,a[maxn],fa[maxn],bi[maxn],sm[maxn];
//bi数组存最大值,sm数组存最小值,num数组存最小编号
int finddad(int x)//找父亲,路径压缩
{
if(x==fa[x])
return x;
return fa[x]=finddad(fa[x]);
}
int findmax(int x)//找最大值
{
return bi[finddad(x)];
}
int findmin(int x)//找最小值
{
return sm[finddad(x)];
}
void unite(int x,int y)//合并
{
if(x<y)//让祖宗的编号最小
{
swap(x,y);
}
fa[x]=y;
bi[x]=bi[y]=max(bi[x],bi[y]);
sm[x]=sm[y]=min(sm[x],sm[y]);
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
fa[i]=i;//初始化
bi[i]=a[i],sm[i]=a[i];
}
for(int i=1;i<=m;i++)
{
int u,v;
scanf("%d %d",&u,&v);
int x=max(findmax(u),findmax(v));
int y=min(findmin(u),findmin(v));
u=finddad(u);//合并祖宗
v=finddad(v);
if(x-y<=k)//满足可以合并的条件
{
unite(u,v);
}
}
for(int i=1;i<=n;i++)
{
int x=finddad(i);
int y=bi[x]-sm[x];
printf("%d %d\n",x,y);
}
return 0;
}