并查集+优先队列+启发式合并 || 罗马游戏 || BZOJ 1455 || Luogu p2713

题面:P2713 罗马游戏

题解:

超级大水题啊,特别水。。

并查集维护每个人在哪个团里,优先队列维护每个团最低分和最低分是哪位,然后每次判断一下哪些人死了,随便写写就行

并查集在Merge时可以用启发式合并,就是把小的团往大的团并,这样显然会更优。当然不写启发式合并应该也能过,就是慢一点。

然后我们也可以写一个按秩合并让它更快233但是没有必要

代码:

 #include<cstdio>
#include<iostream>
#include<queue>
using namespace std;
inline int rd(){
int x=;char c=getchar();
while(c<''||c>'')c=getchar();
while(c>=''&&c<=''){x=x*+c-''; c=getchar();}
return x;
}
const int maxn=,maxm=;
int N,M,fa[maxn],A,B,f1,f2;
bool Died[maxn];
char o[];
struct Peo{
int id,data;
bool operator < (const Peo&a)const{
return a.data<data;
}
}peo;
priority_queue<Peo>pri[maxn];
inline int getf(int n){
if(fa[n]==n) return n;
fa[n]=getf(fa[n]);
return fa[n];
}
int main(){
N=rd();
for(int i=;i<=N;i++){
fa[i]=i;
peo.id=i; peo.data=rd();
pri[i].push(peo);
}
M=rd();
while(M--){
scanf("%s",o);
if(o[]=='M'){
A=rd(); B=rd();
f1=getf(A); f2=getf(B);
if(Died[A] || Died[B] || f1==f2)
continue;
if(pri[f1].size()>pri[f2].size()) swap(f1,f2);
while(!pri[f1].empty()){
if(!Died[(pri[f1].top()).id])
pri[f2].push(pri[f1].top());
pri[f1].pop();
}
fa[f1]=f2;
}
else{
A=rd();
if(Died[A]){
printf("0\n");
continue;
}
f1=getf(A);
if(!pri[f1].empty()){
printf("%d\n",(pri[f1].top()).data);
Died[(pri[f1].top()).id]=;
pri[f1].pop();
}
else printf("0\n");
}
}
return ;
}

By:AlenaNuna

上一篇:给echarts加个“全屏展示”


下一篇:如何面试前端工程师:GitHub 很重要