[FROM WOJ]#2161 罗马游戏(bzoj1455)

传送门

可并堆模板题

SOL
直接用可并堆做。
2个操作

  1. 合并2个集合
  2. 查询1个点所在集合的最小值,并删除该点,如果这个点已经被
    删除则输出0
    集合合并用并查集实现就好了,至于最小值——堆来维护,手写堆。
    裸的左偏树,然而不会……
#include<bits/stdc++.h>
using namespace std;
#define N 1000200
inline int rd(){
	int data=0,w=1;static char ch=0;
	ch=getchar();
	while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
	if(ch=='-')w=-1,ch=getchar();
	while(ch>='0'&&ch<='9')data=(data<<3)+(data<<1)+ch-'0',ch=getchar();
	return data*w;
}
int n,m,rt[N],vis[N];
char ch[10];
int f[N];
int find(int x){return f[x]==x? x:f[x]=find(f[x]);}
struct tree{int l,r,d,w;}t[N];
int merge(int k1,int k2){
	if(!k1||!k2)return k1+k2;
	if(t[k1].w>t[k2].w)swap(k1,k2);
	t[k1].r=merge(t[k1].r,k2);
	if(t[t[k1].l].d<t[t[k1].r].d)swap(t[k1].l,t[k1].r);
	t[k1].d=t[k1].r+1;
	return k1;	
}
void del (int &x){x=merge(t[x].l,t[x].r);}
int main(){
//	freopen("play.in","r",stdin);
//	freopen("play.out","w",stdout);
	n=rd();
	for(int register i=1;i<=n;i++){
		f[i]=i;
		rt[i]=i;
		t[i].w=rd();
	}
	m=rd();
	while(m--){
		scanf("%s",ch);
		if(ch[0]=='M'){
			int x=rd(),y=rd();
			if(vis[x]||vis[y])continue;
			x=find(x),y=find(y);
			if(x==y)continue;
			f[x]=y;
			rt[y]=merge(rt[x],rt[y]);
		}
		else{
			int x=rd();
			if(vis[x])printf("0\n");
			else{
				x=find(x);
				printf("%d\n",t[rt[x]].w);
				vis[rt[x]]=1;
				del(rt[x]);
			}
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值