Luogu P1456 Monkey King

左偏树。

并查集维护每个元素所在左偏树的根。每次取出堆顶除二再 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.19

posted @ 2020-01-19 18:02  LuitaryiJack  阅读(220)  评论(0编辑  收藏  举报