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\n", ans[i]);
113         }
114         //puts("");
115      }
116      return 0;
117 }

 

资源下载链接为: https://pan.quark.cn/s/3d8e22c21839 随着 Web UI 框架(如 EasyUI、JqueryUI、Ext、DWZ 等)的不断发展与成熟,系统界面的统一化设计逐渐成为可能,同时代码生成器也能够生成符合统一规范的界面。在这种背景下,“代码生成 + 手工合并”的半智能开发模式正逐渐成为新的开发趋势。通过代码生成器,单表数据模型以及一对多数据模型的增删改查功能可以被直接生成并投入使用,这能够有效节省大约 80% 的开发工作量,从而显著提升开发效率。 JEECG(J2EE Code Generation)是一款基于代码生成器的智能开发平台。它引领了一种全新的开发模式,即从在线编码(Online Coding)到代码生成器生成代码,再到手工合并(Merge)的智能开发流程。该平台能够帮助开发者解决 Java 项目中大约 90% 的重复性工作,让开发者可以将更多的精力集中在业务逻辑的实现上。它不仅能够快速提高开发效率,帮助公司节省大量的人力成本,同时也保持了开发的灵活性。 JEECG 的核心宗旨是:对于简单的功能,可以通过在线编码配置来实现;对于复杂的功能,则利用代码生成器生成代码后,再进行手工合并;对于复杂的流程业务,采用表单自定义的方式进行处理,而业务流程则通过工作流来实现,并且可以扩展出任务接口,供开发者编写具体的业务逻辑。通过这种方式,JEECG 实现了流程任务节点和任务接口的灵活配置,既保证了开发的高效性,又兼顾了项目的灵活性和可扩展性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值