题目大意:
给你一棵树,求任意两结点u,v之间的距离。
源代码:
/*DFS+RMQ(最近公共祖先)*/ /* 注: (1):Index[x]:表示标号x的结点最早出现的位置 (2):R[]:按dfs访问顺序存每个结点的标号 (3):depth[x]:表示标号x的结点离root的距离 (4):Id[u]=v:表示输入时的u结点被标号为v */ /*AC代码:344ms*/ #include <iostream> #include <cstdio> #include <algorithm> #include <memory.h> #include <cmath> #define MAXN 40005 #define min(a,b) (a<b?a:b) using namespace std; struct edge { int u,v,w,next; }E[3*MAXN]; int head[MAXN],ecnt; int N,M,Q,cnt,num; int Index[MAXN],R[2*MAXN],depth[MAXN],Id[MAXN]; int Min[2*MAXN][30]; bool vis[MAXN]; //-----------------返回区间最大最小值-----------------// void RMQ_Init()//O(nlogn) { int i,j,m; for(i=1;i<=2*N;i++) Min[i][0]=R[i]; m=(int)(log((double)2*N)/log(2.0)); for(i=1;i<=m;i++) { for(j=1;j+(1<<i)-1<=2*N;j++) Min[j][i]=min(Min[j][i-1],Min[j+(1<<(i-1))][i-1]); } } int RMQ_min(int l,int r)//O(1) { int m=(int)(log((double)(r-l+1))/log(2.0)); return min(Min[l][m],Min[r-(1<<m)+1][m]); } //----------------------------------------------------// void Insert(int u,int v,int w) { E[ecnt].u=u; E[ecnt].v=v; E[ecnt].w=w; E[ecnt].next=head[u]; head[u]=ecnt++; } void Init() { int i,u,v,w; char ss[5]; memset(head,-1,sizeof(head));ecnt=0; for(i=1;i<=M;i++) { scanf("%d%d%d%s",&u,&v,&w,ss); Insert(u,v,w); Insert(v,u,w); } } void dfs(int u,int dep) { int i,v; depth[Id[u]]=dep; R[++num]=Id[u]; Index[Id[u]]=num;//第一次出现的位子 for(i=head[u];i!=-1;i=E[i].next) { v=E[i].v; if(!vis[v]) { vis[v]=true; Id[v]=++cnt;//标号 dfs(v,dep+E[i].w); R[++num]=Id[u]; } } } void swap(int &a,int &b) { int t; t=a;a=b;b=t; } void Solve() { int u,v; memset(vis,false,sizeof(vis)); cnt=num=0; Id[1]=++cnt; vis[1]=true; dfs(1,0); RMQ_Init(); scanf("%d",&Q); while(Q--) { scanf("%d%d",&u,&v); if(Index[Id[u]]>Index[Id[v]]) swap(u,v); int x=RMQ_min(Index[Id[u]],Index[Id[v]]); printf("%d\n",depth[Id[u]]+depth[Id[v]]-2*depth[x]); } } int main() { while(scanf("%d%d",&N,&M)!=EOF) { Init(); Solve(); } return 0; }