【HDU1512/ZOJ2334】Monkey King-左偏树-可合并堆
Problem Monkey King
Solution
本题是裸的左偏树,一个模板就可以过了。对于每个操作对节点先删除/2再合并。
注意本题在HDU上评测特别坑,是多组数据,而且经常出现MLE的情况。很可能是其中初始化的问题。
斜堆可以更快。具体请查询IOI2015黄源河集训队论文。
AC Code
#include "iostream" #include "cstdio" using namespace std; struct LeftistTree{ int dist,n,lc,rc,fa; }a[100010]; int find(int x){ while(a[x].fa!=x)x=a[x].fa; return x; } int n,m; int x,y,ans,fx,fy,u,v,dx,dy; int merge(int x,int y){ if(x==0)return y; if(y==0)return x; if(a[x].n<a[y].n)swap(x,y); a[x].rc=merge(a[x].rc,y); a[a[x].rc].fa=x; if(a[a[x].lc].dist<a[a[x].rc].dist)swap(a[x].lc,a[x].rc); if(a[x].rc!=0)a[x].dist=a[a[x].rc].dist+1; else a[x].dist=0; return x; } int delt(int x){ int ret=merge(a[x].lc,a[x].rc); a[a[x].lc].fa=ret; a[a[x].rc].fa=ret; a[x].lc=a[x].rc=a[x].dist=0; a[x].fa=x; return ret; } int main(){ while(~scanf("%d",&n)){ a[0].lc=0;a[0].rc=0;a[0].fa=0; for(int i=1;i<=n;i++)scanf("%d",&a[i].n),a[i].fa=i,a[i].dist=0,a[i].lc=0,a[i].rc=0; scanf("%d",&m); for(int i=1;i<=m;i++){ scanf("%d%d",&x,&y); fx=find(x),fy=find(y); if(fx==fy)printf("-1\n");else{ dx=delt(fx),dy=delt(fy); a[fx].n/=2; a[fy].n/=2; dx=merge(dx,fx); dy=merge(dy,fy); ans=merge(dx,dy); printf("%d\n",a[ans].n); } } } }