zoukankan      html  css  js  c++  java
  • HDU 2586 How far away? LCA 转化成RMQ

    链接:http://acm.hdu.edu.cn/showproblem.php?pid=2586

    【题意】

          给出一个N 个和N-1条边的连通图,询问任意两点间的距离。N<=40000 。

    【分析】

         点太多了,用最短路算法来求超时。只够求一个点的单源最短路,而且不能用O(n2)的算法。正确的做法就是求出两点的最近公共祖先,利用点v到树的根节点距离dis[v]来换算。设要求的两点分别为u和v, 那么u和v的距离d=dis[u]+dis[v]-2*dis[LCA(u,v)]

         现在还有一个问题就是输入是一个图,并不是一棵树,怎么有根节点?怎么确定父子关系?
         这个挺好办的,随便选一个点当根节点,从这个节点开始分层遍历,这样就有树的结构了。求dis数组我原先是用单源最短路来求的,不过仔细想下,因为原图就是一棵树,从根节点到任意点的路径是唯一的,于是就可以用递推的方式求的,在分层遍历中计算就好了。遍历递归的层数有点多,可能会爆栈。

         这里我使用LCA转RMQ的方法来求的。

    【代码】

      1 #pragma comment(linker, "/STACK:1024000000,1024000000") //扩栈
      2 #include <stdio.h>
      3 #include <string.h>
      4 #include <vector>
      5 #include <cmath>
      6 using namespace std;
      7 int n,m;
      8 struct edge
      9 {
     10     int d,v,next;
     11     edge(){}
     12     edge(int _d,int _v,int _next)
     13     {
     14         d=_d;v=_v;next=_next;
     15     }
     16 }data[80003];
     17 int map[40003];
     18 int pool;
     19 void addedge(int s,int e,int v)
     20 {
     21     int t=map[s];
     22     data[pool++]=edge(e,v,t);
     23     map[s]=pool-1;
     24 }
     25 vector<int> f;
     26 vector<int> b;
     27 bool ifv[40003];
     28 int pos[40003];
     29 int dis[40003];
     30 void dfs(int cur,int c)
     31 {
     32     if (cur<0 || cur>=n) return;
     33     ifv[cur]=true;
     34     pos[cur]=(int)f.size();
     35     f.push_back(cur);
     36     b.push_back(c);
     37     int p=map[cur];
     38     while (p!=-1)
     39     {
     40        if (!ifv[data[p].d])
     41        {
     42            dis[data[p].d]=dis[cur]+data[p].v;
     43            dfs(data[p].d,c+1);
     44            f.push_back(cur);
     45            b.push_back(c);
     46        }
     47         p=data[p].next;
     48     }
     49 }
     50 int rmq[80003][17];
     51 void makermq(int n,int bitn)
     52 {
     53    for (int i=0; i<n; ++i)
     54        rmq[i][0]=b[i];
     55    for (int j=1; j<bitn; ++j)
     56      for (int i=0; i<n; ++i)
     57      {
     58         if (i+(1<<(j-1))>=n) break;
     59         rmq[i][j]=min(rmq[i][j-1],rmq[i+(1<<(j-1))][j-1]);
     60      }
     61 }
     62 int query(int s,int e)
     63 {
     64     int k=(int)((log(e-s+1.0)/log(2.0)));
     65     return min(rmq[s][k],rmq[e-(1<<k)+1][k]);
     66 }
     67 int main()
     68 {
     69     int T;
     70     scanf("%d",&T);
     71     while (T--)
     72     {
     73         pool=0;
     74         f.clear();
     75         b.clear();
     76         memset(map,-1,sizeof map);
     77         memset(ifv,0,sizeof ifv);
     78         scanf("%d%d",&n,&m);
     79         int s,e,v;
     80         for (int i=0;i<n-1;++i)
     81         {
     82             scanf("%d%d%d",&s,&e,&v);
     83             addedge(s-1,e-1,v);
     84             addedge(e-1,s-1,v);
     85         }
     86         dis[0]=0;
     87         dfs(0,0);
     88         makermq(b.size(),(int)(log((double)b.size())/log(2.0)));
     89         for (int i=0;i<m;++i)
     90         {
     91             int u,v;
     92             scanf("%d%d",&u,&v);
     93             --u;--v;
     94             int s=pos[u];
     95             int e=pos[v];
     96             if (s>e) swap(s,e);
     97             int k=query(s,e);
     98             k=f[k];
     99             int ans=dis[u]+dis[v]-2*dis[k];
    100             printf("%d
    ",ans);
    101         }
    102     }
    103 }
    View Code
  • 相关阅读:
    XSD文件生成C#VO实体类
    WPF根据Oracle数据库的表,生成CS文件小工具
    【求助】WPF 在XP下 有的Textbox光标会消失
    【转】oracle中in和exists的区别
    Spire.DOC生成表格测试
    【转】C#调用Windows图片和传真查看器打开图片
    WPF MVVM下做发送短信小按钮
    SignalR Progress
    C# readonly
    Settings.settings
  • 原文地址:https://www.cnblogs.com/wuminye/p/3526176.html
Copyright © 2011-2022 走看看