zoj 2334 Monkey King(左偏树+并查集)

感想及学习资料详见:http://blog.csdn.net/zxy_snow/archive/2011/01/22/6158479.aspx

 

纠结了一天了,这题终于A掉了。

 

昨天看到这题,用了一堆方法之后,SF,SF,SF = =。。一搜,左偏树。神马东东,第一次听说 = =。。。

 

印了个论文,自己看。。然后自己敲,用指针。。。SF,SF,SF。。。不知道为啥。。

 

好吧。刚才搜到一个用int型当指针的。。理解着不难,我改了改,居然A了 = =。。。YM。。3S多。。

 

理解差不多了。重点是合并操作,一定要写对啊!!!

 

#include <stdio.h> #include <stdlib.h> #include <iostream> #include <string.h> #define MAX 100010 using namespace std; typedef struct KING{ int s,dis; int r,l; }KING; KING k[MAX]; int n,m,pre[MAX]; void init() { int i; for(i=0; i<=n; i++) pre[i] = i; memset(k,'/0',sizeof(k)); } int Merge( int a, int b ) //左偏树合并操作 { if( a == 0 ) return b; if( b == 0 ) return a; if( k[b].s > k[a].s ) swap(a,b); k[a].r = Merge(k[a].r,b); pre[k[a].r] = a; if( k[k[a].l].dis < k[k[a].r].dis ) swap(k[a].r,k[a].l); if( k[a].r == 0 ) k[a].dis = 0; else k[a].dis = k[k[a].r].dis + 1; return a; } int Max(int a) // 合并左右子树,取出最大节点后的操作 { return Merge( k[a].l, k[a].r ); } int find(int x)// 寻找前驱 { while( x != pre[x] ) x = pre[x]; return x; } int Process(int a,int b) { int x = find(a),y = find(b); int p,xx,yy,tmp; pre[a] = x; pre[b] = y; // Save time operation. if( x == y ) return -1; k[x].s /= 2; tmp = Max(x); k[x].r = k[x].l = k[x].dis = 0; xx = Merge(tmp,x); // 合并新节点和原来的树 k[y].s /= 2; tmp = Max(y); k[y].r = k[y].l = k[x].dis = 0; yy = Merge(tmp,y); // 合并新节点和原来的树 p = Merge(xx,yy); // 合并上面的两棵树 pre[xx] = pre[yy] = pre[x] = pre[y] = pre[a] = per[b] = p; //更改前驱 return k[p].s; } int main() { int i,s,a,b,ans; while( scanf("%d",&n) != EOF ) { init(); for(i=1; i<=n; i++) scanf("%d",&k[i].s); scanf("%d",&m); while( m-- ) { scanf("%d%d",&a,&b); ans = Process(a,b); printf("%d/n",ans); } } return 0; }  

你可能感兴趣的:(zoj 2334 Monkey King(左偏树+并查集))