BZOJ1455 罗马游戏 左偏树 可并堆
欢迎访问~原文出处——博客园-zhouzhendong
去博客园看该题解
题目传送门 - BZOJ1455
题意概括
n个人,2种操作。
一种是合并两个人团,一种是杀死某一个人团的最弱的人。
题解
左偏树裸题。
直接上板子。
代码
#include <cstring> #include <cstdio> #include <algorithm> #include <cstdlib> #include <cmath> using namespace std; const int N=1000005; bool isd(char ch){ return '0'<=ch&&ch<='9'; } void read(int &x){ x=0; char ch=getchar(); while (!isd(ch)) ch=getchar(); while (isd(ch)) x=(x<<1)+(x<<3)+ch-48,ch=getchar(); } int n,m,killed[N]; int fa[N],ls[N],rs[N],npl[N],val[N]; int getf(int a){ while (fa[a]) a=fa[a]; return a; } int merge(int a,int b){ if (!a||!b) return a+b; if (val[a]>val[b]) swap(a,b); rs[a]=merge(rs[a],b); fa[rs[a]]=fa[ls[a]]=a; if (npl[rs[a]]>npl[ls[a]]) swap(rs[a],ls[a]); npl[a]=npl[rs[a]]+1; return a; } int main(){ scanf("%d",&n); for (int i=1;i<=n;i++) read(val[i]),fa[i]=ls[i]=rs[i]=npl[i]=0; memset(killed,0,sizeof killed); scanf("%d",&m); for (int i=1;i<=m;i++){ char op[2]; int a,b; scanf("%s%d",op,&a); if (op[0]=='K'){ if (killed[a]){ puts("0"); continue; } a=getf(a); killed[a]=1; printf("%d\n",val[a]); fa[ls[a]]=fa[rs[a]]=0; merge(ls[a],rs[a]); ls[a]=rs[a]=npl[a]=0; } else { scanf("%d",&b); if (!killed[a]&&!killed[b]&&getf(a)!=getf(b)) merge(getf(a),getf(b)); } } return 0; }