1. 程式人生 > >[HDU2586] How far away ?{LCA.tarjan演算法/倍增演算法}

[HDU2586] How far away ?{LCA.tarjan演算法/倍增演算法}

文章目錄

題目

http://acm.hdu.edu.cn/showproblem.php?pid=2586


解題思路

倍增演算法 O ( ( n

+ m ) l o g   n ) O((n+m)log\ n)

LCA.tarjan演算法 O ( n + m ) O(n+m)

這個 t

a r j a n tarjan 不是縮點的 t a r j a n tarjan

注意:倍增是線上演算法,tarjan是離線演算法


程式碼倍增(TLE)

#include<cstdio>
#include<cmath>
#include<queue>
#include<algorithm>
#include<string>
#define rr register 
using namespace std;
const int size=40010; 
int f[size][20],d[size],dist[size]; 
int ver[size>>1],nex[size>>1],edge[size>>1],head[size]; 
int T,n,m,tot,t; 
queue<int> q; 
void add(int x,int y,int z)
{ ver[++tot]=y; edge[tot]=z; nex[tot]=head[x]; head[x]=tot; }
inline int read()
{
	int p=0,b=1; char c=getchar(); 
	while (!isdigit(c)) {if (c=='-') b=-1; c=getchar();}
	while (isdigit(c)) p=(p<<3)+(p<<1)+c-48,c=getchar(); 
	return p*b; 
}
void write(int x){if (x>9) write(x/10); putchar(x%10+48);}
void bfs(){
	q.push(1); d[1]=1; 
	while (q.size()){
		int x=q.front(); q.pop(); 
		for (rr int i=head[x];i;i=nex[i]){
			int y=ver[i]; 
			if (d[y]) continue; 
			d[y]=d[x]+1; dist[y]=dist[x]+edge[i]; f[y][0]=x; 
			for (int j=1;j<=t;j++) f[y][j]=f[f[y][j-1]][j-1]; 
			q.push(y); 
		}
	}
}
inline int lca(int x,int y)
{
	if (d[x]>d[y]) swap(x,y); 
	for (rr int i=t;i>=0;i--) 
	  if (d[f[y][i]]>=d[x]) y=f[y][i]; 
	if (x==y) return x; 
	for (rr int i=t;i>=0;i--)
	  if (f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
	return f[x][0]; 
}
int main()
{
	T=read(); 
	while (T--){
		n=read(),m=read(); 
		t=(int)log2(n)+1; tot=0; 
		for (rr int i=1;i<=n;i++) head[i]=d[i]=dist[i]=0; 
		for (rr int i=1;i<n;i++) 
		{
			int x=read(),y=read(),z=read(); 
			add(x,y,z),add(y,x,z); 
		}
		bfs(); 
		for (rr int i=1;i<=m;putchar('\n'),i++)	
		{int x=read(),y=read(); write(dist[x]+dist[y]-2*dist[lca(x,y)]);}
	}
	return 0; 
}

程式碼tarjan演算法(AC)

t a n j a n tanjan 演算法本質上是使用並查集對“向上標記法”的優化

#include<vector>
#include<cstdio>
#define Size 50010
using namespace std; 
int ver[Size*2],Next[Size*2],edge[Size*2],head[Size]; 
int fa[Size],d[Size],v[Size],lca[Size],ans[Size]; 
vector<int> query[Size],query_id[Size]; 
int T,n,m,tot,t; 
void addd(int x,int y,int z){
	ver[++tot]=y; edge[tot]=z; Next[tot]=head[x]; head[x]=tot; 
}
void add_query(int x,int y,int id){
	query[x].push_back(y),query_id[x].push_back(id); 
	query[y].push_back(x),query_id[y].push_back(id); 
}
int get(int x){return (x==fa[x])?x:fa[x]=get(fa[x]);}
void tarjan(int x){
	v[x]=1; 
	for (int i=head[x];i;i=Next[i]){
		int y=ver[i]; 
		if (v[y]) continue; 
		d[y]=d[x]+edge[i]; 
		tarjan(y); 
		fa[y]=x; 
	}
	for (int i=0;i<query[x].size();i++){
		int y=query[x][i],id=query_id[x][i]; 
		if (v[y]==2){
			int lca=get(y); 
			ans[id]=min(ans[id],d[x]+d[y]-2*d[lca]); 
		}
	}
	v[x]=2; 
}
int main()
{
	scanf("%d",&T); 
	while (T--)	{
		scanf("%d%d",&n,&m); 
		for (int i=1;i<=n;i++){
			head[i]=0; fa[i]=i; v[i]=0; query[i].clear(),query_id[i].clear(); 
		}
		tot=0; 
		for (int i=1;i<n;i++){
			int x,y,z; 
			scanf("%d%d%d",&x,&y,&z); 
			addd(x,y,z),addd(y,x,z); 
		}
		for (int i=1;i<=m;i++){
			int x,y; 
			scanf("%d%d",&x,&y); 
			if (x==y) ans[i]=0; 
			else {
				add_query(x,y,i); 
				ans[i]=1<<30; 
			}
		}
		tarjan(1); 
		for (int i=1;i<=m;i++) printf("%d\n",ans[i]);
	}
}