[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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章