HDU 2874 LCA转RMQ裸题

题意: 给定无环无向 不一定连通的图,求任意点间最短距离

 

n个点 m条无向边 que个询问

下面u v dis 为边及边长

 

下面que行

u v表示u v点最近距离

 

思路:

LCA转RMQ ,用并查集判断点是否连通

 

#include <iostream> 
#include<cstdio> 
#include<string.h>
#include<math.h>

#define N 10010
using namespace std; 
inline int Max(int a,int b){return a>b?a:b;}
inline int Min(int a,int b){return a<b?a:b;}

struct Edge{
	int from, to, dis, nex;
}edge[N*2];
int head[N], edgenum;
void addedge(int u, int v, int d){
	Edge E = {u, v, d, head[u]};
	edge[ edgenum ] = E;
	head[u] = edgenum++;
}

int f[N];
int find(int x){return x==f[x] ? x : (f[x] = find(f[x]));}
void Union(int x, int y){
	int fx = find(x), fy = find(y);
	if(fx<fy) f[ fx ] = fy;
	else      f[ fy ] = fx;
}

int deep [N<<1];  //第i个访问的结点的深度   
int index[N<<1];  //第i个访问的结点的编号 
int first[N];     //第i个结点是第几个访问的  
int DIS[N];       //到root的距离
int dp[N<<1][16]; //dp[i][j] 为从 i开始到 i+2^j-1 区间内的最值 , 我们可以讲这段2^j的区间分成两部分长度都为2^(j-1)的相同区间 
int time;
void DFS(int u, int dep){
	index[time] = u;
	deep [time] = dep;

	time ++;
	for(int i = head[u]; i!=-1; i = edge[i].nex)
	{
		int v = edge[i].to;
		if(first[v] == 0)
		{
			first[v] = time;
			DIS[v] = DIS[u] + edge[i].dis;
			DFS(v, dep+1);
			index[time] = u;
			deep [time] = dep;
			time++;
		}
	}
}

//F[i][j] =Max( F[i][j-1],F[i+2^(j-1)][j-1] ),边界条件为F[i][0]=A[i]. 

//由于大的区间是由小的区间得到的,所以预处理时必须按区间长度递增的顺序递推出F[i][j]. 

void RMQ_init(int n){
	int i, j;
	for(i = 1; i <= n; i++)//初始化dp数组
		dp[i][0] = i;
	for(j = 1; 1<<j <= n; j++)
	{
		int k = 1<<(j-1);
		for(i = 1; i+k < n; i++)
		{
			if(deep[dp[i][j-1]] <= deep[dp[i+k][j-1]])
				dp[i][j] = dp[i][j-1];
			else 
				dp[i][j] = dp[i+k][j-1];
		}
	}
}
//查询:求区间[ i , j ]的最值   令 d=(int) log2( j-i+1)    

//我们取靠i的长度为2^d区间 以及靠j的2^d区间内的最大值 ,两个区间内可以存在公共部分 

//则i,j max= Max ( F[i][d] ,F[j-2^d+1,d]) 
int RMQ(int a, int b){
	int dis = abs(b-a) + 1;
	int k = log(double(dis)) / log(2.0);
	if(deep[dp[a][k]] <= deep[dp[b-(1<<k)+1][k]])  
		return dp[a][k];  
	else  
		return dp[b-(1<<k)+1][k];
}
int LCA(int u, int v){
	int fu = first[u], fv = first[v];
	return fu <= fv ? index[ RMQ(fu, fv) ] : index[ RMQ(fv, fu) ];
}

bool Ispoint[N];//i点是否为根节点,是则与虚拟根节点0相连

void init(int n){
	memset(head, -1, sizeof(head)); edgenum = 0;
	memset(Ispoint, 0, sizeof(Ispoint));
	memset(first, 0, sizeof(first));
	for(int i = 1; i <= n; i++)f[i] = i;
}

int main() 
{ 
	int i, j, n, que, m, u, v, d;
	int root = 0;
	while(~scanf("%d%d%d",&n,&m,&que)) 
	{
		init(n);
		while(m--)
		{
			scanf("%d %d %d",&u, &v, &d);
			addedge(u, v, d);	addedge(v, u, d);
			Union(u, v);
		}
		for(i = 1; i <= n; i++)find(i);
		for(i = 1; i <= n; i++)Ispoint[ f[i] ] = true;
		for(i = 1; i <= n; i++)
			if(Ispoint[i])
				addedge(root, i, 0);

		time = 1;
		first[root] = time;
		DIS[root] = 0;
		DFS(root, 0);
		RMQ_init(time-1);

		while(que--){
			scanf("%d %d",&u, &v);
			if(f[u] != f[v]){printf("Not connected\n");continue;}
			if(u == v){printf("0\n");continue;}
			printf("%d\n",DIS[u]+DIS[v] - 2*DIS[ LCA(u, v) ]);
		}
	} 
	return 0; 
}


你可能感兴趣的:(HDU 2874 LCA转RMQ裸题)