zoukankan      html  css  js  c++  java
  • [codevs1036]商务旅行<LCA:tarjan&倍增>

    题目链接:http://codevs.cn/problem/1036/

    今天翻箱倒柜的把这题翻出来做了,以前做的时候没怎么理解,所以今天来重做一下

    这题是一个LCA裸题,基本上就把另一道裸题小机房的树拿出来改一改就行

    但LCA也有两种方式,倍增和tarjan,倍增我个人觉得很好理解,tarjan就有点迷了

    所以我就用了两种方式打这一道题

    倍增:

    倍增的做法就是数组f[i][j]表示从i点往上走2^j次方个点可以到达哪个点,

    然后进行一个树上倍增,记录下一个深度dep,然后让我们求的两点到同一深度,如果是同一点就return

    不是同一点就倍增,倍增这个位置的操作和rmq差不多了,就是找到可以最大跳跃的深度,然后不断找。。直到差一个深度到最近公共祖先

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<iostream>
     5 #include<cmath>
     6 #include<stack>
     7 #include<queue>
     8 #include<cstdlib> 
     9 #define maxn 30005
    10 using namespace std;
    11 
    12 struct edge{
    13     int u,v,nxt;
    14 }e[maxn*3];
    15 
    16 int n,m,a[maxn],now[maxn],f[maxn][33];
    17 int head[maxn],dep[maxn],vis[maxn],ans;
    18 
    19 int tot; 
    20 void adde(int u,int v){
    21     e[tot]=(edge){u,v,head[u]};
    22     head[u]=tot++;
    23 }
    24 
    25 void first(){
    26     for(int j=1;j<=32;j++){
    27         for(int i=1;i<=n;i++){
    28             f[i][j]=f[f[i][j-1]][j-1];
    29         }
    30     }
    31 }
    32 
    33 void build(int u){    
    34     for(int i=head[u];i!=-1;i=e[i].nxt){
    35         int v=e[i].v;
    36         if(!vis[v]){
    37             f[v][0]=u;
    38             dep[v]=dep[u]+1;
    39             vis[v]=1;
    40             build(v);
    41         }
    42     }
    43 }
    44 
    45 int up(int x,int d){
    46     for(int i=1;i<=d;i++)
    47         x=f[x][0];
    48     return x;
    49 }
    50 
    51 int find(int x,int y){
    52     if(dep[x]<dep[y])swap(x,y);//手动使x深度深一些
    53     if(dep[x]!=dep[y]){
    54         int dd=dep[x]-dep[y];
    55         x=up(x,dd);
    56     }
    57     if(x==y){return x;}
    58     for(int j=16;j>=0;j--){
    59         if(f[x][j]!=f[y][j]){
    60             x=f[x][j];y=f[y][j];
    61         }
    62     }
    63     return f[x][0];
    64 }
    65 
    66 int main(){
    67     memset(head,-1,sizeof(head));
    68     memset(dep,0,sizeof(dep));
    69     scanf("%d",&n);
    70     for(int i=1;i<n;i++){
    71         int x,y;
    72         scanf("%d%d",&x,&y);
    73         adde(x,y);adde(y,x);
    74     }vis[1]=1;
    75     build(1);
    76     first();
    77     scanf("%d",&m);
    78     now[0]=1;
    79     for(int i=1;i<=m;i++){
    80         scanf("%d",&now[i]);
    81         int lca=find(now[i-1],now[i]);
    82         ans+=dep[now[i-1]]+dep[now[i]]-2*dep[lca];
    83     }
    84     printf("%d",ans);
    85 }
    倍增

    tarjan:

    虽然有些大佬觉得tarjan比倍增好理解,可能是由于我太弱导致我不能理解tarjan,说实话我觉得tarjan这个算法本身就很迷

    tarjan的步骤:

    1.判断与u相连的点,如果没来过就继续往深搜索下去

    2.用并查集维护u,v的关系,讲两个点合并,将v标记来过

    3.查找与u有询问关系的点,如果那个点已经被标记来过就继续

    4.这时候找到的v的所属的并查集数组fa[v]储存的就是u,v的最近公共祖先

    5.这时候u,v的距离就是u的深度+v的深度-两个最近公共祖先深度

      dep[u]+dep[v]-2*dep[fa[v]];

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 #include<iostream>
     5 #include<cmath>
     6 #include<stack>
     7 #include<queue>
     8 #include<cstdlib> 
     9 #define maxn 30005
    10 using namespace std;
    11 
    12 struct node{
    13     int u,v,nxt,w;
    14 }e[maxn*2],q[maxn*2];
    15 
    16 int ans,n,m,head[maxn],heaq[maxn],dep[maxn];
    17 int low[maxn],dfn[maxn],fa[maxn],num;
    18 int now[maxn],cnt,vis[maxn],vise[maxn];
    19 
    20 int tot;
    21 void adde(int u,int v){
    22     e[tot]=(node){u,v,head[u],0};
    23     head[u]=tot;tot++;
    24 }
    25 
    26 int toq;
    27 void addp(int u,int v,int w){
    28     q[toq]=(node){u,v,heaq[u],w};
    29     heaq[u]=toq;toq++;
    30 }
    31 
    32 int find(int x){
    33     if(x==fa[x])return x;
    34     return fa[x]=find(fa[x]);
    35 }
    36 
    37 void tarjan(int u){
    38     num++;fa[u]=u;
    39     dfn[u]=low[u]=num;vis[u]=1;
    40     for(int i=head[u];i!=-1;i=e[i].nxt){
    41         int v=e[i].v;
    42         if(!dfn[v]){
    43             dep[v]=dep[u]+1;
    44             tarjan(v);
    45             fa[v]=u;
    46         }
    47     }
    48     for(int i=heaq[u];i!=-1;i=q[i].nxt ){
    49         int v=q[i].v;
    50         if(vis[v]&&!vise[q[i].w]){
    51             vise[q[i].w]=1;
    52             ans+=dep[v]+dep[u]-2*dep[find(v)];
    53         }
    54     }
    55     
    56 }
    57 
    58 int main(){
    59     memset(head,-1,sizeof(head));
    60     memset(heaq,-1,sizeof(heaq));
    61     scanf("%d",&n);
    62     for(int i=1;i<n;i++){
    63         int x,y;
    64         scanf("%d%d",&x,&y);
    65         adde(x,y);adde(y,x);
    66     }
    67     scanf("%d",&m);
    68     for(int i=1;i<=m;i++){
    69         scanf("%d",&now[i]);
    70         if(i==1&&now[i]!=1)addp(1,now[i],i);
    71         else {
    72             addp(now[i-1],now[i],i);addp(now[i],now[i-1],i);
    73         }
    74     }dep[1]=0;
    75     tarjan(1);
    76     printf("%d",ans);
    77 }
    View Code

    我一个同学教导我,如果你tarjan不理解就画图推,还是推不出来就背就行了,反正又不难背

  • 相关阅读:
    c# GDI+简单绘图(二)
    ProE 工程图教程系列4 ProE不能导出dwg等格式的解决办法
    McAfee卸载工具及卡巴KIS2009注册码
    Vista下修改网卡MAC地址
    开机后出现Spooler Subsystem App 的解决办法
    微软office 2007在线编辑平台Office Live Workspace(docx转doc格式)
    美丽的草原风电场————内蒙古锡林浩特阿巴嘎旗风电场
    ProE官方网站系列视频教程
    [转]Stimator:评估您的网站/博客的价值
    关注苏迪曼杯,关注Lining为羽毛球队打造的衣服
  • 原文地址:https://www.cnblogs.com/Danzel-Aria233/p/7774194.html
Copyright © 2011-2022 走看看