题意:给你n个人,m次匹配,对每次匹配,找出一个人能够认识的最多人。
题解:并查集!然后需要优先队列进行具体维护
#include <iostream>
#include <queue>
#define int long long
using namespace std;
const int N = 1e6+10;
int n;
int pre[N];
int f[N];
//并查集初始化,全部指向自己的父亲节点,在这里看来就是自己
void Init()
{
for(int i=1;i<=n;i++) pre[i]=i,f[i]=1;
}
//合并->写一个函数找到根节点
int root(int x)
{
//核心优化,路径压缩
int rx = x;
while(pre[rx]!=rx) rx = pre[rx];
pre[x]=rx;
return rx;
}
//将u,v节点合并
void merge1(int u, int v)
{
pre[root(u)] = root(v);
}
int rootsum()
{
int cnt = 0;
for(int i=1;i<=n;i++){
if(pre[i]==i) cnt++;
}
return cnt;
}
int tot=1;
signed main() {
cin>>n;
Init();
int m;
cin>>m;
for(int i=1;i<=m;i++){
int r1,r2;
cin>>r1>>r2;
//如果根相等,看需要加几条边。
//如果根不相等,很自然的用并查集
r1 = root(r1);
r2 = root(r2);
//如果两人已经认识了可以多加一条边
if(r1==r2){
tot++;
}else{
//如果不认识就正常并查集的操作
pre[r1]=r2;//pre[1]=2;//pre[2]=3;
//然后加上这个人所认识的人的数目
f[r2]+=f[r1];//f[2]=1;//f[3]=3;
}
//优先队列维护单调性,要加入的肯定是认识的人多的鸭
priority_queue<int>s;
for(int i=1;i<=n;i++){
//就是如果这是根节点,就加入都认识的
if(pre[i]==i)//pre[2]=2;
s.push(f[i]);//f[2]=2
}
int ans = 0;
//tot是有两条边连在一起的时候,一般是都连在一起的
for(int i=1;i<=tot;i++){
//都连在一起就加一下栈顶8⃣️
ans+=s.top();
//然后该出栈的就出栈8⃣️
s.pop();
}
//认识的人当然要减去自己鸭
printf("%lld\n",ans-1);
}
return 0;
//优先队列求最大情况,然后tot;
//1 2
//2 3
}