hdu 2874 Connections between cities (LCA转RMQ)

纠结了N久 的题目,终于过了,LCA转RMQ的思想

首先,求出欧拉序列F[]以及深度序列B[],同时,用pos[]记录每一个节点第一次出现的位置(在欧拉序列中的位置);

之后,就是LCA转化为RMQ的问题了,LCA(u,v)=F(RMQ(B,pos[u],pos[v]))

ps:pos[u]<pos[v]:

深度序列中,2个点之间的最小深度就是最近公共祖先

View Code
#include<iostream>
#include<algorithm>
#include<vector>
#include<math.h>
#define MAXN 10010
using namespace std;
struct node
{
int v,w;
node(int a=0,int b=0):v(a),w(b){}
};
vector<node> g[MAXN];
int f[MAXN],dis[MAXN],n,dp[MAXN*2][20];
int F[MAXN*2],B[MAXN*2],pos[MAXN*2],bn;
bool vis[MAXN];
//F[]保存dfs产生的欧拉序列,dis保存每个节点到根的距离,B[]保存与F[]对应的节点的深度,pos[]保存每一个节点在欧拉序列在第一次出现的位置
void init()
{
for(int i=1;i<=n;i++)
{
f[i]=i;
dis[i]=0;
vis[i]=false;
}
}
int find(int x)
{
if(x==f[x])
return f[x];
f[x]=find(f[x]);
return f[x];
}
void Union(int x,int y)
{
int a=find(x);
int b=find(y);
if(a==b) return ;
f[a]=b;
}
void dfs(int cur,int deep,int len)
{
int num=g[cur].size();
vis[cur]=true;
dis[cur]=len;
F[bn]=cur;
B[bn]=deep;
pos[cur]=bn;
bn++;
for(int i=0;i<num;i++)
{
if(!vis[g[cur][i].v])
{
dfs(g[cur][i].v,deep+1,len+g[cur][i].w);
F[bn]=cur;
B[bn++]=deep;
}
}
}
void init_RMQ()
{
memset(dp,0,sizeof(dp));
for(int i=1;i<=bn;i++)
dp[i][0]=i;
for(int j=1;j<=log((double)(bn+1))/log(2.0);j++)
{
int limit=bn+1-(1<<j);
for(int i=1;i<=limit;i++)
{
int x=dp[i][j-1];
int y=dp[i+(1<<(j-1))][j-1];
dp[i][j]=B[x]<B[y]?x:y;
}
}
}
int RMQ(int a,int b)//注意,RMQ返回的是深度序列的下标
{
if(a>b) {
swap(a,b);
}
int k=(int)(log((double)(b-a+1))/log(2.0));
int x=dp[a][k];
int y=dp[b+1-(1<<k)][k];
return B[x]<B[y]?x:y;
}
int main()
{
int m,k,u,v,w;
while(scanf("%d %d %d",&n,&m,&k)==3)
{
init();
for(int i=1;i<=m;i++)
{
scanf("%d %d %d",&u,&v,&w);
Union(u,v);
g[u].push_back(node(v,w));
g[v].push_back(node(u,w));
}
for(int i=1;i<=n;i++)//将森林转化为树
{
if(f[i]==i)
{
g[0].push_back(node(i,0));
g[i].push_back(node(0,0));
}
}
bn=1;
dfs(0,0,0);
bn--;
init_RMQ();//初始化RMQ
while(k--)
{
scanf("%d %d",&u,&v);
int x=find(u),y=find(v);
if(x!=y){//用并查集判断是否连通
printf("Not connected\n");
continue;
}
int t=RMQ(pos[u],pos[v]);//用RMQ找出最近公共祖先
//if(F[t]==0)俩种方式都可以判断
//{
// puts("Not connected");
// continue;
//}
printf("%d\n",dis[u]+dis[v]-2*dis[F[t]]);
}
for(int i=0;i<=n;i++)
g[i].clear();
}
return 0;
}
原文地址:https://www.cnblogs.com/nanke/p/2373241.html