左偏树。
并查集维护每个元素所在左偏树的根。每次取出堆顶除二再 merge
回去。然后 merge
两个点所在的堆。
#include<iostream>
#include<cstdio>
#define R register int
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
register char s; while(!isdigit(s=getchar())) f=s=='-'?-1:f;
do x=x*10+(s^48); while(isdigit(s=getchar())); return x*f;
} const int N=100010;
int n,m;
int ls[N],rs[N],vl[N],fa[N],d[N];
inline int merge(int x,int y) {
if(!x||!y) return x+y;
if(vl[x]<vl[y]) swap(x,y);
rs[x]=merge(rs[x],y);
if(d[ls[x]]<d[rs[x]]) swap(ls[x],rs[x]);
d[x]=d[rs[x]]+1; return x;
}
inline int getf(int x) {return fa[x]==x?x:fa[x]=getf(fa[x]);}
inline void main() {
while(~scanf("%d",&n)) {
d[0]=-1;
for(R i=1;i<=n;++i)
vl[i]=g(),fa[i]=i,ls[i]=rs[i]=d[i]=0;
m=g();
for(R i=1,x,y,tmp,rt,tr;i<=m;++i) {
x=g(),y=g();
x=getf(x),y=getf(y);
if(x==y) {puts("-1"); continue;}
vl[x]>>=1;
tmp=merge(ls[x],rs[x]);
fa[ls[x]]=fa[rs[x]]=tmp;
ls[x]=rs[x]=d[x]=0;
tr=merge(tmp,x);
fa[tmp]=fa[x]=tr;
vl[y]>>=1;
tmp=merge(ls[y],rs[y]);
fa[ls[y]]=fa[rs[y]]=tmp;
ls[y]=rs[y]=d[y]=0;
rt=merge(tmp,y);
fa[tmp]=fa[y]=rt;
tmp=merge(tr,rt);
fa[tr]=fa[rt]=tmp;
printf("%d\n",vl[tmp]);
}
}
}
} signed main() {Luitaryi::main(); return 0;}
2020.01.18
原文地址:https://www.cnblogs.com/Jackpei/p/12215095.html
时间: 2024-10-10 22:36:28