您的位置:首页 > 其它

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

2011-01-22 15:14 609 查看
感想及学习资料详见: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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: