zoukankan      html  css  js  c++  java
  • 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
    ",query(u,v));
    87         }
    88     }
    89 }
  • 相关阅读:
    BZOJ 3529 [Sdoi2014]数表
    bzoj 3195 [Jxoi2012]奇怪的道路
    BZOJ 4720 [Noip2016]换教室
    BZOJ 2160 拉拉队排练
    BZOJ 1031 [JSOI2007]字符加密Cipher 后缀数组教程
    BZOJ 1002 [FJOI2007]轮状病毒
    欧拉定理、拓展欧拉定理及其应用(欧拉降幂法)
    算术基本定理解析及其应用
    The 15th Zhejiang Provincial Collegiate Programming Contest(部分题解)
    网络流解析及其应用
  • 原文地址:https://www.cnblogs.com/computer-luo/p/9802019.html
Copyright © 2011-2022 走看看