并查集 AcWing 837. 连通块中点的数量
给定一个包含 n 个点(编号为 1∼n)的无向图,初始时图中没有边。
现在要进行 m 个操作,操作共有三种:
C a b,在点 a 和点 b 之间连一条边,a和 b 可能相等;
Q1 a b,询问点 a 和点 b 是否在同一个连通块中,a和 b 可能相等;
Q2 a,询问点 a 所在连通块中点的数量;
输入格式
第一行输入整数 n 和 m。
接下来 m 行,每行包含一个操作指令,指令为 C a b,Q1 a b 或 Q2 a 中的一种。
输出格式
对于每个询问指令 Q1 a b,如果 a 和 b 在同一个连通块中,则输出 Yes,否则输出 No。
对于每个询问指令 Q2 a,输出一个整数表示点 a 所在连通块中点的数量
每个结果占一行。
#include<iostream>
using namespace std;
const int N=100010;
int n,m;
int p[N],size[N];
int find (int x)
{
if (p[x]!=x) p[x]=find(p[x]);
return p[x];
}
int main()
{
scanf ("%d%d",&n,&m);
for (int i=1;i<=n;i++)
{
p[i]=i;
size[i]=1;
}
while (m--)
{
char op[2];
int a,b;
scanf ("%s",op);
if (op[0]=='C')
{
scanf ("%d%d",&a,&b);
if (find(a)==find(b)) continue;
size[find(b)]+=size[find(a)];
p[find (a)]=find (b);
}
else if (op[1]=='1')
{
scanf ("%d%d",&a,&b);
if (find(a)==find(b)) puts ("Yes");
else puts("No");
}
else
{
scanf ("%d",&a);
printf ("%d",size[find(a)]);
}
}
return 0;
}
合并集合操作(C
操作指令):
当op[0] == 'C'
时,表示要进行合并集合的操作,接着通过scanf ("%d%d", &a, &b);
读取要合并的两个元素a
和b
。
先通过find
函数分别找到元素a
和b
所在集合的根节点,若这两个根节点相同(即find(a) == find(b)
),说明它们已经在同一个集合中了,直接执行continue
跳过本次循环,不做重复合并操作。
若两个元素所在集合不同,那么执行size[find(b)] += size[find(a)];
,将元素a
所在集合的大小累加到元素b
所在集合的大小上(这里通过find
函数找到对应的集合根节点,再对size
数组中对应的元素进行操作,以获取和更新集合大小信息),然后执行p[find(a)] = find(b);
,把元素a
所在集合的根节点的父节点设置为元素b
所在集合的根节点,从而实现将元素a
所在的集合合并到元素b
所在的集合中。
查询元素是否在同一集合操作(Q1
操作指令):
当op[1] == '1'
时,表示要查询两个元素是否在同一个集合中,通过scanf ("%d%d", &a, &b);
读取要查询的两个元素a
和b
。
然后通过if (find(a) == find(b)) puts("Yes");
判断元素a
和b
是否在同一个集合中,即先通过find
函数分别找到它们所在集合的根节点,再比较这两个根节点是否相同,如果相同,说明a
和b
在同一个集合中,输出Yes
;否则输出No
。
查询集合大小操作(Q2
操作指令):
当操作指令既不符合C
也不符合Q1
时(也就是op[1]
不是1
的情况),表示要查询给定元素所在集合的大小,先通过scanf ("%d", &a);
读取要查询的元素a
。
再通过printf ("%d", size[find(a)]);
输出元素a
所在集合的大小,这里同样先通过find
函数找到元素a
所在集合的根节点,然后从size
数组中获取对应根节点记录的集合大小信息并输出。
堆 AcWing 838. 堆排序
输入一个长度为 𝑛 的整数数列,从小到大输出前 𝑚 小的数。
输入格式
第一行包含整数 𝑛 和 𝑚。
第二行包含 𝑛 个整数,表示整数数列。
输出格式
共一行,包含 𝑚 个整数,表示整数数列中前 𝑚 小的数。
#include<iostream>
#include<algorithm>
using namespace std;
const int N=100010;
int n,m;
int h[N],size;
void down (int u)
{
int t=u;
if (u*2<=size && h[u*2]<h[t]) t=u*2;
if (u*2+1<=size && h[u*2+1]<h[t]) t=u*2+1;
if (u!=t)
{
swap (h[u],h[t]);
down (t);
}
}
void up (int u)
{
while (u/2 && h[u/2]>h[u])
{
swap (u/2,u);
u/=2;
}
}
int main()
{
scanf ("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf ("%d",h[i]);
size=n;
for (int i=n/2;i;i--) down(i);
while (m--)
{
printf ("%d",h[1]);
h[1]=h[size];
size--;
down(1);
}
return 0;
}