HDU 2586 How far away ? << LCA转RMQ+ST表 求树上任两点最短距离裸题

此题还有LCA+tarjin离线查询做法,详见这里

关于ST表

解决RMQ问题,dp[i][j]表示从第i位开始长度为(1<<j)的区间的最值

维护的时候采用倍增思想,维护dp[i][j+1]=opt(dp[i][j],dp[i+(1<<j)][j])

查询的时候,两端点为l,r,则长度len=r-l,寻找一个k,使(1<<k)大于等于len/2,这样就使得 [l,l+(1<<k)]和[r-(1<<k),r]覆盖整个区间

然后此时,就可以直接用st表查了,ans=opt(dp[l][k],dp[r-(1<<k)][k])

关于LCA转RMQ

用到三个数组

dfsn[i] 表示dfs序,表示第i个访问的节点,此处需要注意的是回溯时也要记录

dist[i] 表示深度,节点i的深度

st[i] 表示节点i第一次出现的位置

然后在dfsn上做RMQ,用dist作为排序规则

这样即是在两节点之间寻找一个深度最小的点,那么这个点就是他们的LCA了

此题代码

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=4e4+7;
 4 struct Edge{
 5     int to,len;
 6 };
 7 
 8 vector<Edge> G[maxn];
 9 int n;
10 int dfsn[maxn*4];
11 int dist[maxn];
12 int st[maxn];
13 int tot;
14 int dp[maxn*4][20];
15 void init()
16 {
17     for(int i=0;i<=n;i++)
18         G[i].clear();
19     memset(dfsn,0,sizeof(dfsn));
20     memset(dist,0,sizeof(dist));
21     tot=0;
22 }
23 void dfs(int u,int fa)
24 {
25     st[u]=++tot;
26     dfsn[tot]=u;
27     for(int i=0;i<G[u].size();i++)
28     {
29         Edge &v=G[u][i];
30         if(v.to==fa) continue;
31         dist[v.to]=dist[u]+v.len;
32         dfs(v.to,u);
33         dfsn[++tot]=u;
34     }
35 }
36 void rmq()
37 {
38     for(int i=1;i<=tot;i++)
39         dp[i][0]=dfsn[i];
40     for(int j=0;(1<<j)<=tot;j++)
41     {
42         for(int i=1;i+(1<<j)<=tot;i++)
43         {
44             if(dist[dp[i][j]]<dist[dp[i+(1<<j)][j]])
45                 dp[i][j+1]=dp[i][j];
46             else dp[i][j+1]=dp[i+(1<<j)][j];
47         }
48     }
49 }
50 int query(int u,int v)
51 {
52     int ss=u,tt=v;
53     u=st[u],v=st[v];
54     if(u>v) swap(u,v);
55     int len=v-u;
56     int k=0;
57     while((1<<k)<len/2)
58         k++;
59     int LCA;
60     if(dist[dp[u][k]]<dist[dp[v-(1<<k)][k]])
61         LCA=dp[u][k];
62     else LCA=dp[v-(1<<k)][k];
63     return dist[ss]+dist[tt]-2*dist[LCA];
64 }
65 int main()
66 {
67     int T;
68     scanf("%d",&T);
69     while(T--)
70     {
71         int q;
72         scanf("%d%d",&n,&q);
73         init();
74         for(int i=1,u,v,len;i<n;i++)
75         {
76             scanf("%d%d%d",&u,&v,&len);
77             G[u].push_back(Edge {v,len});
78             G[v].push_back(Edge {u,len});
79         }
80         dfs(1,-1);
81         rmq();
82         while(q--)
83         {
84             int u,v;
85             scanf("%d%d",&u,&v);
86             printf("%d\n",query(u,v));
87         }
88     }
89 }

 

posted @ 2018-10-17 09:11  computer_luo  阅读(133)  评论(0编辑  收藏  举报