zoukankan      html  css  js  c++  java
  • HDU-2586-裸LCA入门-tarjan离线

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

    给出一颗树和边权,询问两点距离。

        考虑tarjan离线做法,做法很巧妙,当前进行到u,对他的儿子v,当v子树tarjan完成之后把v合并到u上。当遍历完所有v之后,对与u有关的询问进行查找,若第二个询问点v被访问过,那么lca(u,v)就是v目前被合并到的根上。还有记录d[u]表示根到u的距离。

      最后答案就是d[u]+d[v]-2*d[lca(u,v)]。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<map>
     5 #include<set>
     6 #include<stack>
     7 #include<deque>
     8 #include<bitset>
     9 #include<unordered_map>
    10 #include<unordered_set>
    11 #include<queue>
    12 #include<cstdlib>
    13 #include<ctype.h>
    14 #include<ctime>
    15 #include<functional>
    16 #include<algorithm>
    17 #include<bits/stdc++.h>
    18 using namespace std;
    19 #define LL long long 
    20 #define pii pair<int,int>
    21 #define mp make_pair
    22 #define pb push_back
    23 #define fi first
    24 #define se second
    25 #define inf 0x3f3f3f3f
    26 #define debug puts("debug")
    27 #define mid ((L+R)>>1)
    28 #define lc (id<<1)
    29 #define rc (id<<1|1)
    30 const int maxn=40010;
    31 const int maxm=50050;
    32 const double PI=acos(-1.0);
    33 const double eps=1e-6;
    34 const LL mod=1e9+7;
    35 LL gcd(LL a,LL b){return b==0?a:gcd(b,a%b);}
    36 LL lcm(LL a,LL b){return a/gcd(a,b)*b;}
    37 LL qpow(LL a,LL b,LL c){LL r=1; for(;b;b>>=1,a=a*a%c)if(b&1)r=r*a%c;return r;}
    38 template<class T>
    39 void prt(T v){for(auto x:v)cout<<x<<' ';cout<<endl;}
    40 struct Edge{int u,v,w,next;};
    41 
    42 vector<pii>g[maxn],q[maxn];
    43 int d[maxn],f[maxn],qu[220],qv[220],ans[220];
    44 bool vis[maxn];
    45 int getf(int u){return f[u]==u?u:f[u]=getf(f[u]);}
    46 void tarjan(int u){
    47     vis[u]=1;
    48     for(pii e:g[u]){
    49         int v=e.fi,w=e.se;
    50         if(!vis[v]){
    51             d[v]=d[u]+w;
    52             tarjan(v);
    53             f[v]=u;
    54         }
    55     }
    56     for(pii e:q[u]){
    57         int v=e.fi,id=e.se;
    58         if(vis[v]){
    59             ans[id]=getf(v);
    60         }
    61     }
    62 }
    63 int main(){
    64     int t,n,m,i,j,u,v,w;
    65     scanf("%d",&t);
    66     while(t--){
    67         scanf("%d%d",&n,&m);
    68         for(i=1;i<=n;++i){
    69             g[i].clear();
    70             q[i].clear();
    71             f[i]=i;
    72             vis[i]=0;
    73         }
    74         for(i=1;i<n;++i){
    75             scanf("%d%d%d",&u,&v,&w);
    76             g[u].pb(mp(v,w));
    77             g[v].pb(mp(u,w));
    78         }
    79         for(i=1;i<=m;++i){
    80             scanf("%d%d",qu+i,qv+i);
    81             q[qu[i]].pb(mp(qv[i],i));
    82             q[qv[i]].pb(mp(qu[i],i));
    83         }
    84         tarjan(1);
    85         for(i=1;i<=m;++i){
    86             printf("%d
    ",d[qu[i]]+d[qv[i]]-2*d[ans[i]]);
    87         }
    88     }
    89     return 0;
    90 }

    接着用ST在线做法又做了一遍。如果题目强制在线的话,tarjan做法就gg了,我们提前不知道询问便无法离线做了。

    ST做法是每次访问到一个节点就记录下当前的节点值和深度,当查询lca(u,v)的时候,先找到u和v第一次访问到的位置L和R(L<=R),

    然后在[L,R]中找到一个深度最小的点,他对应的节点值w=lca(u,v)。RMQ问题,使用ST处理O(nlog(n))。询问就可以O(1)啦。

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<map>
      5 #include<set>
      6 #include<stack>
      7 #include<deque>
      8 #include<bitset>
      9 #include<unordered_map>
     10 #include<unordered_set>
     11 #include<queue>
     12 #include<cstdlib>
     13 #include<ctype.h>
     14 #include<ctime>
     15 #include<functional>
     16 #include<algorithm>
     17 #include<bits/stdc++.h>
     18 using namespace std;
     19 #define LL long long 
     20 #define pii pair<int,int>
     21 #define mp make_pair
     22 #define pb push_back
     23 #define fi first
     24 #define se second
     25 #define inf 0x3f3f3f3f
     26 #define debug puts("debug")
     27 #define mid ((L+R)>>1)
     28 #define lc (id<<1)
     29 #define rc (id<<1|1)
     30 const int maxn=40010;
     31 const int maxm=50050;
     32 const double PI=acos(-1.0);
     33 const double eps=1e-6;
     34 const LL mod=1e9+7;
     35 LL gcd(LL a,LL b){return b==0?a:gcd(b,a%b);}
     36 LL lcm(LL a,LL b){return a/gcd(a,b)*b;}
     37 LL qpow(LL a,LL b,LL c){LL r=1; for(;b;b>>=1,a=a*a%c)if(b&1)r=r*a%c;return r;}
     38 template<class T>
     39 void prt(T v){for(auto x:v)cout<<x<<' ';cout<<endl;}
     40 struct Edge{int u,v,w,next;};
     41 
     42 vector<pii>g[maxn];
     43 vector<int>dep,idx;
     44 int f[maxn*2][20],d[maxn],p[maxn];
     45 void dfs(int u,int o,int fa){
     46     p[u]=idx.size();
     47     idx.pb(u),dep.pb(o);
     48     for(pii e:g[u]){
     49         int v=e.fi,w=e.se;
     50         if(v!=fa){
     51             d[v]=d[u]+w;
     52             dfs(v,o+1,u);
     53             idx.pb(u),dep.pb(o);
     54         }
     55     }
     56 }
     57 void ST(int n){
     58     for(int i=0;i<n;++i)f[i][0]=i;
     59     for(int j=1;(1<<j)<=n;j++){
     60         for(int i=0;(i+(1<<j)-1)<n;i++){
     61             f[i][j]=dep[f[i][j-1]]<dep[f[i+(1<<(j-1))][j-1]]?f[i][j-1]:f[i+(1<<(j-1))][j-1];
     62         }
     63     }
     64 }
     65 int ask(int L,int R){
     66     int k=0;
     67     while((1<<(1+k))<=R-L+1)k++;
     68     return dep[f[L][k]]<dep[f[R-(1<<k)+1][k]]?idx[f[L][k]]:idx[f[R-(1<<k)+1][k]];
     69 }
     70 int main(){
     71     int t,n,m,i,j,u,v,w;
     72     scanf("%d",&t);
     73     while(t--){
     74         idx.clear();
     75         dep.clear();
     76         scanf("%d%d",&n,&m);
     77         for(i=1;i<=n;++i){
     78             g[i].clear();
     79         }
     80         for(i=1;i<n;++i){
     81             scanf("%d%d%d",&u,&v,&w);
     82             g[u].pb(mp(v,w));
     83             g[v].pb(mp(u,w));
     84         }
     85         dfs(1,1,0);
     86         ST(idx.size());
     87     //    prt(idx);
     88     //    prt(dep);
     89         while(m--){
     90             scanf("%d%d",&u,&v);
     91             int L=p[u],R=p[v];
     92             if(L>R)swap(L,R);
     93             printf("%d
    ",d[u]+d[v]-2*d[ask(L,R)]);
     94         }
     95     }
     96     return 0;
     97 }
     98 /*
     99 5
    100 7 7
    101 1 2 1
    102 1 3 1
    103 2 4 1
    104 2 5 1
    105 5 6 1
    106 5 7 1
    107 */

      综上两种方法而言,我感觉思想都是类似是,就是u-->v这条路一定经过他们的共同祖先,这中间过程中经过若干个点,我们要想办法找到深度最小的那个点,显然他只会被经过一次,就是LCA。

  • 相关阅读:
    【各种排序系列之】归并排序
    【LeetCode练习题】Candy
    【LeetCode练习题】Minimum Window Substring
    【LeetCode练习题】Partition List
    【Java之】多线程学习笔记
    【Java】使用Runtime执行其他程序
    【各种排序系列之】快速排序法
    Bzoj 3389: [Usaco2004 Dec]Cleaning Shifts安排值班 最短路,神题
    Bzoj 1901: Zju2112 Dynamic Rankings 树套树,线段树,平衡树,Treap
    Bzoj 2834: 回家的路 dijkstra,堆优化,分层图,最短路
  • 原文地址:https://www.cnblogs.com/zzqc/p/10078343.html
Copyright © 2011-2022 走看看