zoukankan      html  css  js  c++  java
  • 【NOIP2013/Codevs3287】货车运输-最小生成树(大)-树上倍增

    Problem 树上倍增

    题目大意

    给出一个图,给出若干个点对u,v,求u,v的一条路径,该路径上最小的边权值最大。

    Solution

    看到这个题第一反应是图论。。

    然而,任意路径最小的边权值最大,如果仔细思考的话就会知道,如果两个点相互连通,那么一定走的是最大生成树上的路径,而不会选择其他任何一条路径去走。

    这个是可以非常简单证明的,就不再详述。

    那么既然知道了这个,当然是先建一颗最大生成树啦!

    现在问题来了,Prim&Kruskal,选哪个?

    分析一下,prim复杂度$O(n^2)$,n为总点数。

    Kruskal复杂度$O(mlog_2n)$,m为总边数。

    显而易见,在这一道题目中kruskal更优。

    于是写一个kruskal最大生成树。

    接下来要在这颗树上跑。

    我们设立一个fa数组,其fa[i][j]表示对于i节点,向上的2^j个节点编号是什么。显而易见,fa[i][0]就是i的父亲。

    $$fa[i][j]=fa[fa[i][j-1][j-1]$$

    然后我们还需要一个储存最小值的数组,设立minn数组,其中minn[i][j]表示对于i节点,向上2^j个节点的边最小值

    显而易见,minn[i][0]就表示i节点本身链接父亲边的权值.

    $$minn[i][j]=min(minn[fa[i][j-1]][j-1],minn[i][j-1])$$

    可以看出,这两个数组在O(n)的时间就可以求出来了。

    接下来,对于每一个询问点对,我们只需要倍增求lca,再求两个点到lca路径上最小值,就可以求出答案。

    判断uv谁深度更深,更深深度先跳到同一深度。

    接下来两个一起向上跳,能够跳就跳。

    具体方法可以看代码。

    AC Code

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 using namespace std;
     6 struct kruskal{
     7     int u,v,w;
     8 }ekr[50010];
     9 struct node{
    10     int to,next,w;
    11 }e[20010];
    12 int f[10010],h[10010],dep[10010],n,m,u,v,w,q,ktot=0,tot=0,ans;
    13 int fa[10010][22],minn[10010][22];
    14 void add_kruskal(int u,int v,int w){
    15     ekr[++ktot].u=u;ekr[ktot].v=v;ekr[ktot].w=w;
    16 }
    17 bool cmp(kruskal a,kruskal b){
    18     return a.w>b.w;
    19 }
    20 void add(int u,int v,int w){
    21     e[++tot].to=v;e[tot].next=h[u];h[u]=tot;e[tot].w=w;
    22     e[++tot].to=u;e[tot].next=h[v];h[v]=tot;e[tot].w=w;
    23 }
    24 void initdfs(int x,int last,int we,int depth){
    25     dep[x]=depth;
    26     fa[x][0]=last;
    27     minn[x][0]=we;
    28     for(int i=1;i<=14;i++){
    29         fa[x][i]=fa[fa[x][i-1]][i-1];
    30         minn[x][i]=min(minn[x][i-1],minn[fa[x][i-1]][i-1]);
    31     }
    32     for(int i=h[x];~i;i=e[i].next)
    33         if(e[i].to!=last)initdfs(e[i].to,x,e[i].w,depth+1);
    34 }
    35 void queue(int u,int v){
    36     if(dep[u]<dep[v])swap(u,v);
    37     int dist=dep[u]-dep[v],tmp=0;
    38     while(dist){
    39         if(dist%2==1)ans=min(ans,minn[u][tmp]),u=fa[u][tmp];
    40         tmp++;
    41         dist>>=1;
    42     }
    43     for(int i=14;i>=0;i--){
    44         if(fa[u][i]!=fa[v][i]){
    45             ans=min(min(ans,minn[u][i]),minn[v][i]);
    46             u=fa[u][i];
    47             v=fa[v][i];
    48         }
    49     }
    50     ans=(u==v)?ans:min(min(ans,minn[u][0]),minn[v][0]);
    51 }
    52 int find(int x){
    53     if(f[x]!=x)f[x]=find(f[x]);
    54     return f[x];
    55 }
    56 int main(){
    57 //  freopen("xsy2018.in","r",stdin);
    58     memset(h,-1,sizeof(h));
    59     scanf("%d%d",&n,&m);
    60     for(int i=1;i<=m;i++){
    61         scanf("%d%d%d",&u,&v,&w);
    62         add_kruskal(u,v,w);
    63     }
    64     sort(ekr+1,ekr+ktot+1,cmp);
    65     for(int i=1;i<=n;i++)f[i]=i;
    66     for(int i=1,sum=0;i<=ktot;i++){
    67         int fu=find(ekr[i].u),fv=find(ekr[i].v);
    68         if(fu!=fv){
    69             add(ekr[i].u,ekr[i].v,ekr[i].w);
    70             f[fu]=fv;f[ekr[i].u]=fv;f[ekr[i].v]=fv;
    71             sum++;
    72         }
    73         if(tot==((n-1)<<1))break;
    74     }
    75     initdfs(1,0,233333333,0);
    76     scanf("%d",&q);
    77     for(int i=1;i<=q;i++){
    78         scanf("%d%d",&u,&v);
    79         ans=233333333;
    80         queue(u,v);
    81         printf("%d
    ",(ans==0)?-1:ans);
    82     }
    83 }
  • 相关阅读:
    1、编写一个简单的C++程序
    96. Unique Binary Search Trees
    python 操作redis
    json.loads的一个很有意思的现象
    No changes detected
    leetcode 127 wordladder
    django uwsgi websocket踩坑
    you need to build uWSGI with SSL support to use the websocket handshake api function !!!
    pyinstaller 出现str error
    数据库的读现象
  • 原文地址:https://www.cnblogs.com/skylynf/p/7147762.html
Copyright © 2011-2022 走看看