zoukankan      html  css  js  c++  java
  • HDU 2586 How far away ?【LCA】

    任意门:http://acm.hdu.edu.cn/showproblem.php?pid=2586

    How far away ?

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 24439    Accepted Submission(s): 9739


    Problem Description
    There are n houses in the village and some bidirectional roads connecting them. Every day peole always like to ask like this "How far is it if I want to go from house A to house B"? Usually it hard to answer. But luckily int this village the answer is always unique, since the roads are built in the way that there is a unique simple path("simple" means you can't visit a place twice) between every two houses. Yout task is to answer all these curious people.
     
    Input
    First line is a single integer T(T<=10), indicating the number of test cases.
      For each test case,in the first line there are two numbers n(2<=n<=40000) and m (1<=m<=200),the number of houses and the number of queries. The following n-1 lines each consisting three numbers i,j,k, separated bu a single space, meaning that there is a road connecting house i and house j,with length k(0<k<=40000).The houses are labeled from 1 to n.
      Next m lines each has distinct integers i and j, you areato answer the distance between house i and house j.
     
    Output
    For each test case,output m lines. Each line represents the answer of the query. Output a bland line after each test case.
     
    Sample Input
    2 3 2 1 2 10 3 1 15 1 2 2 3 2 2 1 2 100 1 2 2 1
     
    Sample Output
    10 25 100 100

    题意概括:

    给一颗 N 个结点,N-1条边的树,和 M 次查询(离线)

    解题思路:

    要查询两点到最近公共祖先的距离和,首先要预处理出根结点到各个结点的距离(DFS)

    然后 Tarjan 找出最近的公共祖先,两个结点到根结点的距离之和减去两倍的最近公共祖先到根结点的距离就是该查询的答案了。

    AC code:

      1 #include <cstdio>
      2 #include <iostream>
      3 #include <algorithm>
      4 #include <cstring>
      5 #include <vector>
      6 #define INF 0x3f3f3f3f
      7 #define LL long long
      8 const int MAX_N = 4e4+5;
      9 using namespace std;
     10 
     11 struct Edge{int v, nxt, w;}edge[MAX_N<<1];              //静态邻接表
     12 struct Query
     13 {
     14     int v, id;
     15     Query(){};
     16     Query(int _v, int _id):v(_v), id(_id){};
     17 };
     18 
     19 vector<Query> q[MAX_N];       // !!!                    //查询关系动态二维矩阵
     20 
     21 int head[MAX_N], cnt;                                   //静态邻接表头节点,边数
     22 int dis[MAX_N];                                         //各结点到根结点的距离
     23 int fa[MAX_N];                                          //并查集 祖先数组
     24 bool vis[MAX_N], in[MAX_N];                             //深搜用,找根结点用
     25 int ans[MAX_N];                // !!!                   //各查询答案
     26 int N, M;                                               //结点数,查询数
     27 
     28 void init()
     29 {
     30     memset(head, -1, sizeof(head));                     //初始化
     31     memset(vis, false, sizeof(vis));
     32     memset(in, false, sizeof(in));
     33     memset(dis, 0, sizeof(dis));
     34     memset(ans, 0, sizeof(ans));
     35     cnt = 0;
     36 }
     37 
     38 void AddEdge(int from, int to, int weight)              //静态邻接表加边操作
     39 {
     40     edge[cnt].v = to;
     41     edge[cnt].w = weight;
     42     edge[cnt].nxt = head[from];
     43     head[from] = cnt++;
     44 }
     45 
     46 int getfa(int x)                                        //找祖先
     47 {
     48     int root = x;
     49     while(fa[root] != root) root = fa[root];
     50 
     51     int tmp;
     52     while(fa[x] != root){
     53         tmp = fa[x];
     54         fa[x] = root;
     55         x = tmp;
     56     }
     57     return root;
     58 }
     59 
     60 void dfs(int s)                                         //预处理各根结点到祖先的距离
     61 {
     62     int rt = s;
     63     for(int i = head[s]; i != -1; i = edge[i].nxt){
     64         dis[edge[i].v] = dis[rt] + edge[i].w;
     65         dfs(edge[i].v);
     66     }
     67 }
     68 
     69 void Tarjan(int s)                                      // LCA
     70 {
     71     int root = s;
     72     fa[s] = s;
     73     for(int i = head[s]; i != -1; i = edge[i].nxt){
     74         int Eiv = edge[i].v;
     75         Tarjan(Eiv);
     76         fa[getfa(Eiv)] = s;
     77     }
     78     vis[s] = true;
     79     for(int i = 0; i < q[s].size(); i++){
     80         if(vis[q[s][i].v] && !ans[q[s][i].id]){
     81             ans[q[s][i].id] = dis[q[s][i].v] + dis[s] - 2*dis[getfa(q[s][i].v)];
     82         }
     83     }
     84 }
     85 
     86 int main()
     87 {
     88      int T_case;
     89      scanf("%d", &T_case);
     90      while(T_case--){
     91         init();
     92         scanf("%d %d", &N, &M);
     93         for(int i = 1, u, v, w; i < N; i++){                //建树
     94             scanf("%d %d %d", &u, &v, &w);
     95             AddEdge(u, v, w);
     96             in[v] = true;
     97         }
     98 
     99         for(int i = 1, u, v; i <= M; i++){                  //储存查询信息(离线)
    100             scanf("%d %d", &u, &v);
    101             q[u].push_back(Query(v, i));
    102             q[v].push_back(Query(u, i));
    103         }
    104 
    105         int root = 0;
    106         for(int i = 1; i <= N; i++) if(!in[i]){root = i; break;}    //找树根结点
    107 
    108         dfs(root);              //预处理
    109         Tarjan(root);           //LCA
    110 
    111         for(int i = 1; i <= M; i++){
    112             printf("%d
    ", ans[i]);
    113         }
    114         //puts("");
    115      }
    116      return 0;
    117 }
  • 相关阅读:
    SpringBoot中如何优雅的使用多线程
    ASP.NET MVC经典项目ProDinner项目解析(5)
    ASP.NET MVC经典项目ProDinner项目解析(4)
    ASP.NET MVC经典项目ProDinner项目解析(1)
    ASP.NET MVC经典项目ProDinner项目解析文章索引
    致我们工作中的设计模式之备忘录模式
    致我们工作中的设计模式之适配器模式
    ASP.NET MVC经典项目ProDinner项目解析(3)
    童话进行中的Silverlight
    致我们工作中的设计模式之基本原则职责单一原则
  • 原文地址:https://www.cnblogs.com/ymzjj/p/9744756.html
Copyright © 2011-2022 走看看