1. 程式人生 > >How far away: RMQ 與 LCA

How far away: RMQ 與 LCA

題目連結:How far away

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

RMQ做法

這裡滿足一個性質:對於任意的x,y,他們的lca必定是x,y的路徑上的最淺的點(dep最小)

所以我們就可以記錄路徑(注意將路徑上的數放在一個連續區間裡),然後用倍增就可以找到某一區間的Min值啦

程式碼在這裡:

#include <iostream>
#include <cstdio>
#include <cstring>

using namespace std;
const int maxn=40005;
int n,m,cnt,iindex;
int u[maxn*2],v[maxn*2],w[maxn*2],log2[maxn];
int nxt[maxn*2],head[maxn],dep[maxn];
int vis[maxn*2],f[maxn*2][33],pos[maxn];
void init()
{
	cnt=0;iindex=0;
	memset(head,-1,sizeof(head));
	memset(f,0,sizeof(f));
	memset(dep,0,sizeof(dep));
	memset(pos,0,sizeof(pos));
}
void add_edge(int x,int y,int z)
{
	cnt++;u[cnt]=x;v[cnt]=y;w[cnt]=z;
	nxt[cnt]=head[x];head[x]=cnt;
}
void find(int x,int fa)
{
	iindex++;pos[x]=iindex;vis[iindex]=x;
	for(int i=head[x];i!=-1;i=nxt[i])
	{
		if(v[i]!=fa) 
		{
			dep[v[i]]=dep[x]+w[i];
			find(v[i],x);
			vis[++iindex]=x;
		}
	}
}
void rmq(int len)
{
	for(int i=1;i<=len;i++) f[i][0]=dep[vis[i]];
	for(int j=1;(1<<j)<=len;j++)
	{
		for(int i=1;(i+(1<<j))<=len;i++)
		{
			f[i][j]=min(f[i][j-1],f[i+(1<<(j-1))][j-1]);
		}
	}
}
int lca(int x,int y)
{
	x=pos[x];y=pos[y];if(x>y) swap(x,y);
	int t=log2[y-x+1];
	return min(f[x][t],f[y-(1<<t)+1][t]); 
}
void work()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<n;i++)
	{
		int x,y,z;scanf("%d%d%d",&x,&y,&z);
		add_edge(x,y,z);add_edge(y,x,z);
	}
	find(1,0);rmq(iindex);
	for(int i=1;i<=m;i++)
	{
		int x,y;scanf("%d%d",&x,&y);
		printf("%d\n",dep[x]+dep[y]-2*lca(x,y));
	}
}
int main()
{
	log2[1]=0;for(int i=2;i<maxn;i++) log2[i]=log2[i/2]+1;
	int T;scanf("%d",&T);
	for(int t=1;t<=T;t++)
	{
		init();
		work();	
	}	
	return 0;
} 

LCA做法

這裡不是很想贅述了,就是記錄每個點的深度(dep值),然後找兩個點的lca,x,y之間的距離就是dep[x]+dep[y]-2*lca(x,y)

直接上程式碼:

#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
const int maxn=40005;
int n,m;
struct node
{
	int x,w;
};
vector<node> v[maxn];
int p[maxn][32];int dep[maxn],d[maxn];
void prework()
{
	for(int j=1;j<=31;j++)
	{
		for(int i=1;i<=n;i++)
		{
			p[i][j]=p[p[i][j-1]][j-1];
		}
	}
}
void find(int x,int fa)
{
	p[x][0]=fa;dep[x]=dep[fa]+1;
	for(int i=0;i<v[x].size();i++)
	{
		if(v[x][i].x!=fa)
		{
			d[v[x][i].x]=d[x]+v[x][i].w;
			find(v[x][i].x,x);
		}
	}
}
int lca(int x,int y)
{
	if(dep[x]<dep[y]) swap(x,y);
	int i;for(i=1;(1<<i)<=dep[x];i++);i--;
	for(int j=i;j>=0;j--) if(dep[x]-(1<<j)>=dep[y]) x=p[x][j];
	if(x==y) return x;
	for(int j=i;j>=0;j--)
	{
		if(p[x][j]!=p[y][j])
		{
			x=p[x][j];y=p[y][j];
		}
	}
	return p[x][0];
}
void work()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<n;i++)
	{
		int x,y,z;scanf("%d%d%d",&x,&y,&z);node k;
		k.x=y;k.w=z;
		v[x].push_back(k);
		k.x=x;v[y].push_back(k);
	}
	find(1,0);prework();
	for(int i=1;i<=m;i++)
	{
		int x,y;scanf("%d%d",&x,&y);
		int anc=lca(x,y);
		printf("%d\n",d[x]+d[y]-2*d[anc]);
	}
}
int main()
{
	int T;scanf("%d",&T);
	for(int t=1;t<=T;t++) 
	{
		work();
	}
	return 0;
}

我掉進的坑:多組詢問一定要初始化!初始化!初始化!