zoukankan      html  css  js  c++  java
  • [vijos1460&Metocode P223]拉力赛<LCA>

    题目链接:https://vijos.org/p/1460

        http://oj.fjaxyz.com:3389/problem.php?id=223

    我不禁开始怀疑,这,真的是最近公共祖先的题吗,我是从一个讲解LCA的博客里找到这道题的,然后我就乖乖的用了可爱的LCA倍增,然后我就更加愉快的TLE了。

    【思路】

    判断u,v 的最近公共祖先是不是u,如果是,就加上这条路线。。。

    判断u,v的最近公共祖先是不是u,TLE的代码是用倍增算法做的这个,但是啊,其实我们换一种说法就是判断u是不是v的祖先

    那么这就简单了,想想LCA的离线做法tarjan,里面的dfn数组,储存的是i点的dfs序号,然后实质上其实是前序遍历序号

    怎么判断u是v的祖先?刚刚才提到前序遍历,那我想想后序遍历,前序是根左右,后序是左右根,那么意思就是根在前序是比叶节点序号小,在后序是比叶节点序号大

    于是我们储存数组begn[] ed[]储存点的前序序号和后序序号,如果begn[u]<begn[v]&&ed[u]>ed[v]说明u是v的祖先

    解决了这个问题,接下来就是求距离,我们储存数组dis表示点i到根节点的距离,

    所以u,v距离就是dis[u]+dis[v]-2*dis[lca(u,v)],由于这题满足条件是u为v的祖先,所以距离简化为dis[v]-dis[u]

    LCA倍增算法

     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 10005
    10 #define ll long long
    11 using namespace std;
    12 
    13 struct node{
    14     int u,v;ll w;int nxt;
    15 }e[maxn];
    16 
    17 int head[maxn],n,m,f[maxn][20];
    18 ll dis[maxn],ans;
    19 int cnt,vis[maxn],dep[maxn];
    20 
    21 int tot;
    22 void adde(int u,int v,int w){
    23     e[tot]=(node){u,v,w,head[u]};
    24     head[u]=tot;tot++;
    25 }
    26 
    27 void build(int u){    
    28     for(int i=head[u];i!=-1;i=e[i].nxt){
    29         int v=e[i].v;
    30         if(!vis[v]){
    31             f[v][0]=u;
    32             dis[v]=dis[u]+e[i].w;
    33             dep[v]=dep[u]+1;
    34             vis[v]=1;
    35             build(v);
    36         }
    37     }
    38 }
    39 
    40 void first(){
    41     for(int j=1;j<=16;j++){
    42         for(int i=1;i<=n;i++){
    43             f[i][j]=f[f[i][j-1]][j-1];
    44         }
    45     }
    46 }
    47 
    48 int up(int x,int d){
    49     for(int i=1;i<=d;i++)
    50         x=f[x][0];
    51     return x;
    52 }
    53 
    54 int find(int x,int y){
    55     if(dep[x]<dep[y])swap(x,y);
    56     if(dep[x]!=dep[y]){
    57         int dd=dep[x]-dep[y];
    58         x=up(x,dd);
    59     }
    60     if(x==y){return x;}
    61     for(int j=16;j>=0;j--){
    62         if(f[x][j]!=f[y][j]){
    63             x=f[x][j];y=f[y][j];
    64         }
    65     }
    66     return f[x][0];
    67 }
    68 
    69 ll len(int u,int v){
    70     return dis[v]-dis[u];
    71 }
    72 
    73 int main(){
    74     memset(head,-1,sizeof(head));
    75     scanf("%d%d",&n,&m);
    76     for(int i=1;i<n;i++){
    77         int u,v,w;
    78         scanf("%d%d%d",&u,&v,&w);
    79         adde(u,v,w);
    80     }
    81     build(1);
    82     first();
    83     for(int i=1;i<=m;i++){
    84         int u,v;
    85         scanf("%d%d",&u,&v);
    86         int lca=find(u,v);
    87         if(lca==u){ans+=len(u,v);cnt++;}
    88     }
    89     printf("%d
    %lld",cnt,ans);
    90 }
    倍增(TLE)

    运用前序后序的dfs算法

     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 10005
    10 using namespace std;
    11 
    12 struct node{
    13     int u,v;long long w;int nxt;
    14 }e[maxn];
    15 
    16 int head[maxn],n,m;
    17 int cnt,vis[maxn];
    18 int begn[maxn],ed[maxn];
    19 long long ans,dis[maxn];
    20 
    21 int tot;
    22 void adde(int u,int v,long long w){
    23     e[tot]=(node){u,v,w,head[u]};
    24     head[u]=tot;tot++;
    25 }
    26 
    27 int num,hehe;
    28 void build(int u){    
    29     num++;begn[u]=num;
    30     for(int i=head[u];i!=-1;i=e[i].nxt){
    31         int v=e[i].v;
    32         if(!vis[v]){;
    33             dis[v]=dis[u]+e[i].w;
    34             vis[v]=1;
    35             build(v);
    36         }
    37     }
    38     hehe++;ed[u]=hehe;
    39 }
    40 
    41 int main(){
    42     memset(head,-1,sizeof(head));
    43     scanf("%d%d",&n,&m);
    44     for(int i=1;i<n;i++){
    45         int u,v;long long w;
    46         scanf("%d%d%lld",&u,&v,&w);
    47         adde(u,v,w);
    48     }
    49     build(1);
    50     for(int i=1;i<=m;i++){
    51         int u,v;
    52         scanf("%d%d",&u,&v);
    53         if(begn[u]<=begn[v]&&ed[u]>=ed[v]){
    54             ans+=dis[v]-dis[u];cnt++;
    55         }
    56     }
    57     printf("%d
    %lld",cnt,ans);
    58 }
    AC于vijos

    然后问题就来了,这个在vijos上AC的代码在meto code上还是WA了,我已经放弃了,因为meto code不提供错误数据也不告诉我错了几组,所以我最终还是没有在meto code上成功

  • 相关阅读:
    GZIPInputStream 流未关闭引起的内存泄漏问题
    Java ExcutorService优雅关闭方式
    redis pipline
    LeetCode 30与所有单词相关联的字串
    Scala不使用null 而使用Option,None,Some的好处
    记录: 一次解决整型溢出攻击(使用scala,隐式转换)
    Scala 封装可break和continue的foreach循环
    记录: 百度webuploader 分片文件上传java服务器端(spring mvc)示例的优化
    HBase shell 中的十六进制数值表示
    关于getSystemResource, getResource 的总结
  • 原文地址:https://www.cnblogs.com/Danzel-Aria233/p/7777063.html
Copyright © 2011-2022 走看看