• hdu2874 LCA


    题意:现在有 n 个点与 m 条边的无向无环图,但是图不一定完全连通,边有各自的边权,给出多组询问,查询两点之间的路径权值和,或者输出两点不连通。

    一开始有最短路的想法,但是由于询问有 1e6 组,做单源最短路肯定会爆炸,而 1e4 的边数又觉得 floyd 时间空间都会炸,又因为是无环图,所以就想到了LCA的做法,大量询问让我很自然地就想到了离线Tarjan。由于不连通,就分多次Tarjan,通过标记来实现是否在同一棵树中。离线Tarjan 搞了一发结果就原来的做法估计是因为vector中的pair需要存问题编号或者是vector本身的原因,总之一直 MLE ,看了 discuss 有人提供了一种问题的存储方法,就是将所有问题也像链式前向星的方法存储,而节点编号分别是 0/1,2/3,这样的,只要用 节点编号/2 就能确定是哪个问题的结果。这样A掉了。但是不能忍的是我看见别人的题解里写的做法是直接递归向上爬LCA的做法……而且不是倍增!是一步一步爬的!递归!而且我交了一发还比离线快!这什么数据啊!卡空间不卡时间!暴力都能过!还更快!我不服!

     1 #include<stdio.h>
     2 #include<string.h>
     3 
     4 const int maxn=1e4+1;
     5 const int maxm=2e4+1;
     6 const int maxq=1e6+1;
     7 
     8 int n;
     9 int head[maxn],nxt[maxm],point[maxm],val[maxm],size;
    10 int fa[maxn],dis[maxn];
    11 int vis1[maxn];
    12 int ans[maxq];
    13 int head1[maxn],point1[maxq<<1],nxt1[maxq<<1],size1;
    14 int cnt;
    15 
    16 void init(){
    17     memset(head,-1,sizeof(head));
    18     size=0;
    19     memset(head1,-1,sizeof(head1));
    20     size1=0;
    21     memset(vis1,0,sizeof(vis1));
    22     for(int i=1;i<=n;++i)fa[i]=i;
    23     memset(ans,-1,sizeof(ans));
    24     cnt=0;
    25 }
    26 
    27 void add(int a,int b,int v){
    28     point[size]=b;
    29     val[size]=v;
    30     nxt[size]=head[a];
    31     head[a]=size++;
    32     point[size]=a;
    33     val[size]=v;
    34     nxt[size]=head[b];
    35     head[b]=size++;
    36 }
    37 
    38 int find(int x){
    39     return x==fa[x]?x:fa[x]=find(fa[x]);
    40 }
    41 
    42 void Tarjan(int s,int pre){
    43     for(int i=head[s];~i;i=nxt[i]){
    44         int j=point[i];
    45         if(j!=pre){
    46             dis[j]=dis[s]+val[i];
    47             Tarjan(j,s);
    48             int x=find(j),y=find(s);
    49             if(x!=y)fa[x]=y;
    50         }
    51     }
    52     vis1[s]=cnt;
    53     for(int i=head1[s];~i;i=nxt1[i]){
    54         int j=point1[i];
    55         if(vis1[j]==vis1[s]){
    56             int lca=find(j);
    57             int id=i/2;
    58             ans[id]=dis[s]+dis[j]-2*dis[lca];
    59         }
    60     }
    61 }
    62 
    63 int main(){
    64     int m,k;
    65     while(scanf("%d%d%d",&n,&m,&k)!=EOF){
    66         init();
    67         while(m--){
    68             int a,b,v;
    69             scanf("%d%d%d",&a,&b,&v);
    70             add(a,b,v);
    71         }
    72         for(int i=0;i<k;++i){
    73             int a,b;
    74             scanf("%d%d",&a,&b);
    75             point1[size1]=b;
    76             nxt1[size1]=head1[a];
    77             head1[a]=size1++;
    78             point1[size1]=a;
    79             nxt1[size1]=head1[b];
    80             head1[b]=size1++;
    81         }
    82         for(int i=1;i<=n;++i){
    83             if(!vis1[i]){
    84                 ++cnt;
    85                 dis[i]=0;
    86                 Tarjan(i,0);
    87             }
    88         }
    89         for(int i=0;i<k;++i){
    90             if(ans[i]==-1)printf("Not connected
    ");
    91             else printf("%d
    ",ans[i]);
    92         }
    93     }
    94     return 0;
    95 }
    View Code
  • 相关阅读:
    为什么要选择忍者站群?
    SDCMS1.31 如何发布?
    强大的忍者站群
    出现未能加载“OpenWebKitSharp”是什么原因?
    wordpress发布模块如何使用?
    忍者站群做了百度竞价,岂不是跟站群相违背吗?
    点点博客的发布模块,如何使用?
    为什么有时候明明提示登陆成功,却无法获取分类或无法发布?
    被百度K了,怎么办?
    笔记0611
  • 原文地址:https://www.cnblogs.com/cenariusxz/p/4829694.html
Copyright © 2020-2023  润新知