学习了左偏树,发现及其强大,尤其是插入可以达到O(logN)的时间复杂度,我主要参考的是这些文章点击打开链接,又学到东西了
/******************************************************************************* # Author : Neo Fung # Email : [email protected] # Last modified: 2011-09-27 19:39 # Filename: ZOJ2334 HDU1512 Monkey King.cpp # Description : 左偏树 ******************************************************************************/ // #include "stdafx.h" // #define DEBUG #include <fstream> #include <stdio.h> #include <iostream> #include <string.h> #include <string> #include <memory.h> #define MAX 100100 using namespace std; struct NODE { int r,l,val,dis; }mon[MAX]; int pre[MAX];//用于保存祖先节点,其实这里可以把祖先节点保存在NODE中 int n,m; void init(void) { for(int i=0;i<=n;++i) pre[i]=i; memset(mon,'\0',sizeof(mon)); } int inline find(int x) { return x==pre[x]?x:pre[x]=find(pre[x]); //找到x的祖先节点 } int merge(int a,int b) //合并两个左偏树 { if(a==0) return b; if(b==0) return a; if(mon[a].val<mon[b].val) //由于根节点的值比子孙节点的值大,而且这里是递归把右边的树和左边的树的右子树合并,所以要保证左边的树的根的值比右边的树的根的值大 swap(a,b); mon[a].r=merge(mon[a].r,b);//把右边的树和左边的树的右子树合并 pre[mon[a].r]=a; if( mon[mon[a].l].dis<mon[mon[a].r].dis) swap(mon[a].l, mon[a].r);// 保证右边的树的距离不大于左边的树的距离 if(mon[a].r==0) mon[a].dis=0; else mon[a].dis=mon[mon[a].r].dis+1; return a; } int solve( int a, int b) { int x=find(a),y=find(b); int temp; if(x==y) return -1; mon[x].val /=2; temp=merge(mon[x].l,mon[x].r); mon[x].l=mon[x].r=mon[x].dis=0; int xroot=merge(temp,x); mon[y].val /=2; temp = merge(mon[y].l , mon[y].r); mon[y].l=mon[y].r=mon[y].dis=0; int yroot=merge(temp , y); temp=merge(xroot,yroot); pre[x]=pre[y]=pre[xroot]=pre[yroot]=pre[a]=pre[b]=temp; return mon[temp].val; } int main(void) { #ifdef DEBUG freopen("data.txt","r",stdin); #endif int a,b; while(scanf("%d",&n)!=EOF) { init(); for(int i=1;i<=n;++i) scanf("%d",&mon[i].val); scanf("%d",&m); for(int i=0;i<m;++i) { scanf("%d %d",&a,&b); printf("%d\n",solve(a,b)); } } return 0; }