poj 1986 RMQ&&LCA( 模板题)
给出一棵树
询问 a-b的路径长度是多少
sum【i】记录节点i到根的距离长度
对于每次询问,用RMQ预处理的LCA可以在线回答每个询问, ans=sum[a]+sum[b]-2*sum[LCA(a,b)];
但是这个题目离线的tarjan算法在速度上上拥有巨大的优势,几乎是瞬秒的
View Code
#include<string.h> #include<stdio.h> #include<vector> #include<math.h> using namespace std; const int M =40100; const double inf = 1e20; int min(int a,int b){return a<b?a:b;} int n,k,tdfn,tot; int dp[20][2*M],vis[M]; int B[2*M],LOG[2*M],used[M],F[2*M],pos[M]; vector<pair<int,int> > edge[2*M]; void rmq_init(int n,int num[]) { int i,j; for(j=1;j<=n;j++) dp[0][j]=num[j]; for(j=1;j<=LOG[n];j++) { int limit=n+1-(1<<j); for(i=1;i<=limit;i++) { int x=i+(1<<j>>1); dp[j][i]=min(dp[j-1][x],dp[j-1][i]); } } } int rmq(int l,int r,int num[]) { int m=LOG[r-l+1]; return min(dp[m][l],dp[m][r-(1<<m)+1]); } int sum[M]; void dfs(int s) { int i,t; used[s]=1; int tmp=++tdfn; B[++tot]=tmp;F[tmp]=s; pos[s]=tot; for(i=0;i<edge[s].size();i++) { t=edge[s][i].first; if(used[t]) continue; sum[t]=sum[s]+edge[s][i].second; dfs(t); B[++tot]=tmp;//backtrack } } int lca(int a,int b) { if(pos[a]>pos[b]) swap(a,b); int ans=rmq(pos[a],pos[b],B); return F[ans]; } int main() { int i,n,m,a,b,w; LOG[0]=-1; for(i=1;i<2*M;i++) LOG[i]=LOG[i>>1]+1; while(scanf("%d%d",&n,&m)!=EOF) { for(i=0;i<=n;i++) edge[i].clear(); char str[5]; for(i=0;i<m;i++) { scanf("%d%d%d%s",&a,&b,&w,str); edge[a].push_back(make_pair(b,w)); edge[b].push_back(make_pair(a,w)); } sum[1]=0; tdfn=0; tot=0; memset(used,0,sizeof(used)); dfs(1); rmq_init(tot,B); scanf("%d",&k); while(k--) { scanf("%d%d",&a,&b); printf("%d\n",sum[a]+sum[b]-2*sum[lca(a,b)]); } } return 0; }