• HDU 2586 LCA


     题目大意:

    多点形成一棵树,树上边有权值,给出一堆询问,求出每个询问中两个点的距离

    这里求两个点的距离可以直接理解为求出两个点到根节点的权值之和,再减去2倍的最近公共祖先到根节点的距离

    这是自己第一道lca题目

    学习了两种方法

    第一种在ST算法,利用RMQ思想预处理

     1 /*在线ST算法*/
     2 #pragma comment(linker, "/STACK:102400000,102400000")
     3 #include <cstdio>
     4 #include <iostream>
     5 #include <cstring>
     6 #include <algorithm>
     7 using namespace std;
     8 #define N 40010
     9 
    10 int first[N] , k;
    11 
    12 struct Edge{
    13     int x , y , w , next;
    14     Edge(){}
    15     Edge(int x , int y , int w , int next):x(x),y(y),w(w),next(next){}
    16 }e[N<<1];
    17 
    18 void add_edge(int x , int y , int w)
    19 {
    20     e[k] = Edge(x , y , w , first[x]);
    21     first[x] = k++;
    22 }
    23 int dp[N<<1][28];
    24 int id[N<<1] , dep[N<<1] , dis[N] , No[N] , dfs_clock;
    25 void dfs(int u , int f , int d)
    26 {
    27     id[++dfs_clock] = u , No[u] = dfs_clock , dep[dfs_clock] = d;
    28     for(int i=first[u] ; ~i ; i=e[i].next){
    29         int v = e[i].y;
    30         if(v == f) continue;
    31         dis[v] = dis[u]+e[i].w;
    32         dfs(v , u , d+1);
    33         id[++dfs_clock] = u , dep[dfs_clock] = d;
    34     }
    35 }
    36 
    37 void ST(int n)
    38 {
    39     for(int i=1 ; i<=n ; i++) dp[i][0] = i;
    40     for(int j=1 ; (1<<j)<=n ; j++){
    41         for(int i=1 ; i+(1<<j)-1<=n ; i++){
    42             int a = dp[i][j-1] , b = dp[i+(1<<(j-1))][j-1];
    43             dp[i][j] = dep[a]<dep[b]?a:b;
    44         }
    45     }
    46 }
    47 
    48 int RMQ(int l , int r)
    49 {
    50     int k=0;
    51     while((1<<(k+1))<=r-l+1) k++;
    52     int a = dp[l][k] , b = dp[r-(1<<k)+1][k];
    53     return dep[a]<dep[b]?a:b;
    54 }
    55 
    56 int LCA(int u , int v)
    57 {
    58     int x = No[u] , y = No[v];
    59     if(x>y) swap(x , y);
    60     return id[RMQ(x , y)];
    61 }
    62 
    63 int n , m;
    64 
    65 int main()
    66 {
    67    // freopen("in.txt" , "r" , stdin);
    68     int T , x , y , w;
    69     scanf("%d" , &T);
    70     while(T--)
    71     {
    72         scanf("%d%d" , &n , &m);
    73         memset(first , -1 , sizeof(first));
    74         k = 0;
    75         for(int i=1 ; i<n ; i++){
    76             scanf("%d%d%d" , &x , &y , &w);
    77             add_edge(x , y , w);
    78             add_edge(y , x , w);
    79         }
    80         dfs_clock = 0;
    81         dis[1] = 0;
    82         dfs(1 , 0 , 1);
    83         ST(2*n-1);
    84         while(m--){
    85             scanf("%d%d" , &x , &y);
    86             int anc = LCA(x , y);
    87             printf("%d
    " , dis[x]-2*dis[anc]+dis[y]);
    88         }
    89     }
    90     return 0;
    91 }
    ST算法

    第二种是离线的Tarjan算法,利用并查集的思想解决

     1 /*在线ST算法*/
     2 #pragma comment(linker, "/STACK:102400000,102400000")
     3 #include <cstdio>
     4 #include <iostream>
     5 #include <cstring>
     6 #include <algorithm>
     7 using namespace std;
     8 #define N 40010
     9 #define M 205
    10 int first[N] , k;
    11 
    12 struct Edge{
    13     int x , y , w , next;
    14     Edge(){}
    15     Edge(int x , int y , int w , int next):x(x),y(y),w(w),next(next){}
    16 }e[N<<1];
    17 
    18 int _first[N] , _k;
    19 
    20 struct Que{
    21     int v , lca , next;
    22     Que(){}
    23     Que(int v , int lca , int next):v(v),lca(lca),next(next){}
    24 }eq[M<<1];
    25 
    26 void add_edge(int x , int y , int w)
    27 {
    28     e[k] = Edge(x , y , w , first[x]);
    29     first[x] = k++;
    30 }
    31 
    32 void add_que_edge(int x , int y)
    33 {
    34     eq[_k] = Que(y , 0 , _first[x]);
    35     _first[x] = _k++;
    36 }
    37 
    38 int fa[N] , dis[N];
    39 bool vis[N];
    40 int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
    41 
    42 void tarjan(int u)
    43 {
    44     vis[u] = true , fa[u] = u;
    45     for(int i=first[u] ; ~i ; i=e[i].next){
    46         int v = e[i].y;
    47         if(vis[v]) continue;
    48         dis[v] = dis[u]+e[i].w;
    49         tarjan(v);
    50         fa[v] = u;
    51     }
    52     for(int i=_first[u] ; ~i ; i=eq[i].next){
    53         int v = eq[i].v;
    54         if(vis[v]) eq[i].lca = eq[i^1].lca = find(eq[i].v);
    55     }
    56 }
    57 int n , m;
    58 
    59 int main()
    60 {
    61    // freopen("in.txt" , "r" , stdin);
    62     int T , x , y , w;
    63     scanf("%d" , &T);
    64     while(T--)
    65     {
    66         scanf("%d%d" , &n , &m);
    67         memset(first , -1 , sizeof(first));
    68         k = 0;
    69         for(int i=1 ; i<n ; i++){
    70             scanf("%d%d%d" , &x , &y , &w);
    71             add_edge(x , y , w);
    72             add_edge(y , x , w);
    73         }
    74         memset(_first , -1 , sizeof(_first));
    75         _k = 0;
    76         for(int i=0 ; i<m ; i++){
    77             scanf("%d%d" , &x , &y);
    78             add_que_edge(x , y);
    79             add_que_edge(y , x);
    80         }
    81         memset(vis , 0 , sizeof(vis));
    82         tarjan(1);
    83         for(int i=0 ; i<m*2 ; i+=2){
    84             int lca = eq[i].lca;
    85             printf("%d
    " , dis[eq[i].v]-2*dis[lca]+dis[eq[i^1].v]);
    86         }
    87     }
    88     return 0;
    89 }
    Tarjan算法
  • 相关阅读:
    【反演复习计划】【bzoj2154】Crash的数字表格
    【反演复习计划】【bzoj3529】数表
    【反演复习计划】【bzoj3994】DZY loves maths
    【反演复习计划】【bzoj3994】约数个数和
    【反演复习计划】【bzoj2818】gcd
    【反演复习计划】【bzoj1011】zap-queries
    BZOJ3991: [SDOI2015]寻宝游戏
    BestCoder Round #75
    BZOJ4417: [Shoi2013]超级跳马
    BZOJ4416: [Shoi2013]阶乘字符串
  • 原文地址:https://www.cnblogs.com/CSU3901130321/p/4712771.html
Copyright © 2020-2023  润新知