Spoj 375 Qtree Link - Cut Tree 解法

Qtree第一种解法,采用动态树。详情参考杨哲《Qtree解法的一些研究》。数据结构用Splay Tree。要特别注意理解Link-Cut Tree,尤其是他的Access操作。



#include <stdio.h>
#include <string.h>
#include <queue>
#include <vector>
using namespace std;

#define MAXN 10005

int father[MAXN];
struct ANode
{
	int v;
	int w;
	ANode * next;
	ANode(int _v,int _w,ANode * _next)
	{
		v = _v;
		w = _w;
		next = _next;
	}
}*adj[MAXN];

struct Node
{
	Node * father;
	Node * ch[2];
	bool root;//是不是所在Splay Tree的根节点
	int cost;//此节点到父节点的权值
	int maxcost;//以此节点为根的子树的cost的最大值
}tree[MAXN],*null,Tnull;

void init(Node * p)
{
	p->ch[0] = p->ch[1] = p->father = null;
	p->maxcost = p->cost = 0;
	p->root = true;
}

void bfs()
{
	queue<int> q;
	q.push(1);
	memset(father,-1,sizeof(father));
	father[1] = 0; 
	while(q.size())
	{
		int u = q.front();
		q.pop();
		for(ANode * p = adj[u];p;p = p->next)
		{
			if(father[p->v] == -1)
			{

				father[p->v] = u;
				tree[p->v].father = tree + u;
				tree[p->v].cost = tree[p->v].maxcost = p->w;
				q.push(p->v);
			}
		}
	}
}
void push_up(Node * p)
{
	p->maxcost = max(max(p->ch[0]->maxcost,p->ch[1]->maxcost),p->cost);
}

void rotate(Node * x,int c)
{
	Node * y = x->father;
	y->ch[!c] = x->ch[c];
	if(x->ch[c]!=null)
	{
		x->ch[c]->father = y;
	}
	x->father = y->father;
	if(y->father!=null)
	{
		if(y->father->ch[0] == y)
		{
			y->father->ch[0] = x;
		}
		else if(y->father->ch[1] == y)//一定要用Else If,如果直接用Else会出现错误,因为树本身可能不是二叉树,虽然生成的Splay Tree是
		{
			y->father->ch[1] = x;
		}
	}
	x->ch[c] = y;
	y->father = x;
	push_up(y);
	//push_up(x);
	if(y->root)
	{
		x->root = true;
		y->root = false;
	}
}

void splay(Node * p)
{
	if(p == null)
	{
		return;
	}
	for(;!p->root;)
	{
		if(p->father->root)
		{
			if(p->father->ch[0] == p)
			{
				rotate(p,1);
			}
			else
			{
				rotate(p,0);
			}
		}
		else
		{
			Node * y = p->father;
			Node * z = y->father;
			if(z->ch[0] == y)
			{
				if(y->ch[0] == p)//一字形旋转
				{
					rotate(y,1);
					rotate(p,1);	
				}
				else
				{
					rotate(p,0);
					rotate(p,1);
				}
			}
			else
			{
				if(y->ch[1] == p)
				{
					rotate(y,0);
					rotate(p,0);
				}
				else
				{
					rotate(p,1);
					rotate(p,0);
				}

			}
		}
	}
	push_up(p);
}

void access(Node * u,int flag)
{
	Node * v = null;
	while(u!=null)
	{
		splay(u);
		if(flag == 2)
		{
			if(u->father == null)
			{
				printf("%d\n",max(u->ch[1]->maxcost,v->maxcost));
			}
		}
		u->ch[1]->root = true;
		u->ch[1] = v;
		v->root = false;
		push_up(u);
		v = u;
		u = u->father;
	}
}
void query(int u,int v)
{
	access(tree + u,1);
	access(tree + v,2);

}
void change(int u,int cost)
{
	access(tree + u,1);
	splay(tree + u);
	tree[u].cost = cost;
	push_up(tree + u);
}

vector<pair<int,int> > edge;

int main()
{
	#ifndef ONLINE_JUDGE
		freopen("in.txt","r",stdin);
	#endif
	int T;
	int N;
	int a,b,c;
	char cmd[20];

	scanf("%d",&T);
	null = &Tnull;
	init(null);
	while(T--)
	{
		scanf("%d",&N);
		for(int i=1;i<=N;i++)
		{
			adj[i] = NULL;
			init(&tree[i]);
		}
		edge.clear();
		for(int i=0;i<N-1;i++)
		{
			scanf("%d%d%d",&a,&b,&c);
			adj[a] = new ANode(b,c,adj[a]);
			adj[b] = new ANode(a,c,adj[b]);
			edge.push_back(make_pair(a,b));		
		}
		bfs();
		while(1)
		{
			scanf("%s",cmd);
			if(strcmp(cmd,"QUERY") == 0)
			{
				scanf("%d%d",&a,&b);
				query(a,b);
			}
			if(strcmp(cmd,"CHANGE") == 0)
			{
				scanf("%d%d",&a,&b);
				a--;
				int u = edge[a].first;
				int v = edge[a].second;
				if(father[u] == v)
				{
					change(u,b);
				}
				else if(father[v] == u)
				{
					change(v,b);
				}
			
			}
			if(strcmp(cmd,"DONE")==0)
			{
				break;
			}
		}
			
	}
	return 0;
}

参考资料: http://wenku.baidu.com/view/75906f160b4e767f5acfcedb.html

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值