poj1986Distance Queries(RMQ+LCA)

题目连接:http://poj.org/problem?id=1986

感觉比离线的难理解一些。。

 参考:http://www.cnblogs.com/scau20110726/archive/2013/05/26/3100812.html

   http://www.cnblogs.com/BruceNoOne/archive/2013/07/26/3217486.html

 

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<cmath>
  4 #include<algorithm>
  5 using namespace std;
  6 const int maxn=40008;
  7 int dis[maxn],vis[maxn];
  8 int first[maxn*2],node[maxn*2],dep[maxn*2],dp[maxn*2][25];
  9 struct edge
 10 {
 11     int v,w,nex;
 12 }e[maxn*2];
 13 
 14 int head[maxn];
 15 int cnt;
 16 
 17 void add(int u,int v,int w)
 18 {
 19     e[cnt].v=v;
 20     e[cnt].w=w;
 21     e[cnt].nex=head[u];
 22     head[u]=cnt++;
 23 }
 24 
 25 void dfs(int &id,int u,int d,int w)
 26 {
 27     id++;
 28     node[id]=u;  //树变数组,第一次经过该点
 29     dep[id]=d;  //深度
 30     vis[u]=1;
 31     first[u]=id;  //第一次出现
 32     for(int i=head[u];i!=-1;i=e[i].nex) if(!vis[e[i].v])  //遍历
 33     {
 34         dis[e[i].v]=w+e[i].w;
 35         dfs(id,e[i].v,d+1,dis[e[i].v]); //往下一路到底
 36         id++;
 37         node[id]=u;  //第二次经过该点
 38         dep[id]=d;  //记录深度
 39     }
 40 }
 41 void RMQ_init(int n)
 42 {
 43    int k = log2(n);  // 要选用g++,才能用log2
 44     for(int i=1;i<=n;i++) dp[i][0]=i;  //记录最小值的下标,初始化
 45     for(int j=1;j<=k;j++)
 46         for(int i=1;i+(1<<j)-1<=n;i++)
 47     {
 48         int a=dp[i][j-1];
 49         int b=dp[i+(1<<j-1)][j-1];     //一定要注意位运算优先级
 50         if(dep[a]<dep[b]) dp[i][j]=a;
 51         else dp[i][j]=b;
 52     }
 53 }
 54 
 55 int rmq(int x,int y)
 56 {
 57     int k=log2(y-x+1);
 58     int a=dp[x][k];
 59     int b=dp[y-(1<<k)+1][k];
 60     if(dep[a]<dep[b]) return a;
 61     else return b;
 62 }
 63 
 64 int lca(int a,int b)  //返回最近公共祖先
 65 {
 66     int x=first[a];
 67     int y=first[b];
 68     int k;
 69     if(x<=y)
 70     {
 71         k=rmq(x,y);
 72         return node[k];  
 73     }
 74     else
 75     {
 76         k=rmq(y,x);
 77         return node[k];
 78     }
 79 }
 80 int main()
 81 {
 82     int n,m;
 83     while(scanf("%d%d",&n,&m)!=EOF)
 84     {
 85         cnt=0;
 86         memset(head,-1,sizeof(head));
 87         int u,v,w;
 88         char s[10];
 89         while(m--)
 90         {
 91             scanf("%d%d%d%s",&u,&v,&w,s);
 92             add(u,v,w);
 93             add(v,u,w);
 94         }
 95         int tot=0;
 96         memset(vis,0,sizeof(vis));
 97         memset(dis,0,sizeof(dis));
 98         dfs(tot,1,1,0);
 99         RMQ_init(tot);
100         int k;
101         scanf("%d",&k);
102         while(k--)
103         {
104             scanf("%d%d",&u,&v);
105             printf("%d\n",dis[u]+dis[v]-2*dis[lca(u,v)]);
106 
107         }
108     }
109     return 0;
110 
111 }

 

posted @ 2017-04-11 22:38  yijiull  阅读(154)  评论(0编辑  收藏  举报