acwing c++基础算法笔记 连通块中点的数量 堆排序

并查集 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);读取要合并的两个元素ab

  先通过find函数分别找到元素ab所在集合的根节点,若这两个根节点相同(即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);读取要查询的两个元素ab

  然后通过if (find(a) == find(b)) puts("Yes");判断元素ab是否在同一个集合中,即先通过find函数分别找到它们所在集合的根节点,再比较这两个根节点是否相同,如果相同,说明ab在同一个集合中,输出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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值