LCA模板

一:Tarjan离线求LCA

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define maxn 100080
#define maxm 200160
int first[maxn],dis[maxn],vis[maxn],fa[maxn];
int firstq[maxn];
int vv[maxm],nxt[maxm],ww[maxm];
int vvq[maxm],nxtq[maxm],ansq[maxm];
int e,eq;
void init()
{
	e = eq = 0;
	memset(vis,0,sizeof(vis));
	memset(first,-1,sizeof(first));
	memset(firstq,-1,sizeof(firstq));
}

int find(int x)
{
	if(x == fa[x])	return x;
	return fa[x] = find(fa[x]);
}

void addedge(int u,int v,int w)
{
	vv[e] = v;	ww[e] = w;	nxt[e] = first[u];	first[u] = e++;
	vv[e] = u;	ww[e] = w;	nxt[e] = first[v];	first[v] = e++;
}

void addquery(int u,int v)
{
	vvq[eq] = v;	nxtq[eq] = firstq[u];	firstq[u] = eq++;
	vvq[eq] = u;	nxtq[eq] = firstq[v];	firstq[v] = eq++;	
}

void Tarjan(int u,int pre)
{
	fa[u] = u;
	for(int i = first[u];i != -1;i = nxt[i])
	{
		int v = vv[i];
		if(v == pre)	continue;
		dis[v] = dis[u] + ww[i];
		Tarjan(v,u);
		fa[v] = u;
	}
	vis[u] = 1;
	for(int i = firstq[u];i != -1;i = nxtq[i])
	{
		int v = vvq[i];
		if(vis[v])	ansq[i] = find(v);
	}
}

int main()
{
	freopen("in.txt","r",stdin);
	int n;
	while(scanf("%d",&n)!=EOF)
	{
		init();
		for(int i = 1;i < n;i++)
		{
			int u,v,w;
			scanf("%d%d%d",&u,&v,&w);
			addedge(u,v,w);
		}
		int q;
		scanf("%d",&q);
		for(int i = 1;i <= q;i++)
		{
			int u,v;
			scanf("%d%d",&u,&v);
			addquery(u,v);
		}
		dis[1] = 0;
		Tarjan(1,-1);
		for(int i = 0;i < eq;i+=2)
		{
			if(ansq[i] == 0)	ansq[i] = ansq[i^1];
			printf("%d\n",ansq[i]);
		}
	}
	return 0;
}

二:预处理2的若干次幂祖先。先将u和v中深度大的跳到深度一样。然后一起往上跳。

PS:这里写的不是很好。稍后来改。

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define maxn 100080
#define maxm 200160
int first[maxn],dis[maxn],dep[maxn],fa[maxn][20];
int vv[maxm],ww[maxm],nxt[maxm];
int e;
void init()
{
	e = 0;
	memset(first,-1,sizeof(first));
	memset(dep,-1,sizeof(dep));
	memset(fa,-1,sizeof(fa));
}

void addedge(int u,int v,int w)
{
	vv[e] = v;	ww[e] = w;	nxt[e] = first[u];	first[u] = e++;
	vv[e] = u;	ww[e] = w;	nxt[e] = first[v];	first[v] = e++;
}

void dfs(int u,int pre)
{
	fa[u][0] = pre;
	//祖先初始化
	int pos = 0;
	while(fa[fa[u][pos]][pos] != -1)	
	{
		pos++;
		fa[u][pos] = fa[fa[u][pos-1]][pos-1];
	}
	for(int i = first[u];i != -1;i = nxt[i])
	{
		int v = vv[i];
		if(v == pre)	continue;
		dep[v] = dep[u]+1;
		dis[v] = dis[u] + ww[i];
		dfs(v,u);
	}
}

int lca(int u,int v)
{
	if(dep[u] < dep[v])
		swap(u,v);
	while(dep[u] > dep[v])
	{
		int pos = 0;
		while(fa[u][pos] != -1 && dep[fa[u][pos]] >= dep[v])
			pos++;
		u = fa[u][pos-1];
	}
	//到这里的时候就在同一层了
	while(u != v)
	{
		int pos = 1;
		while(fa[u][pos] != fa[v][pos])
			pos++;
		u = fa[u][pos-1],v = fa[v][pos-1];
	}
	return u;
}

int main()
{
	freopen("in.txt","r",stdin);
	int n;
	while(scanf("%d",&n)!=EOF)
	{
		init();
		for(int i = 1;i < n;i++)
		{
			int u,v,w;
			scanf("%d%d%d",&u,&v,&w);
			addedge(u,v,w);
		}
		int q;
		scanf("%d",&q);
		dis[1] = 0;dep[1] = 0;
		dfs(1,-1);
		for(int i = 1;i <= q;i++)
		{
			int u,v;
			scanf("%d%d",&u,&v);
			printf("%d\n",lca(u,v));
		}
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值