zoukankan      html  css  js  c++  java
  • [Codevs1519]过路费解题报告|最小生成树|LCA

       在某个遥远的国家里,有 n个城市。编号为 1,2,3,…,n。这个国家的政府修建了m 条双向道路,每条道路连接着两个城市。政府规定从城市 S 到城市T需要收取的过路费为所经过城市之间道路长度的最大值。如:A到B长度为 2,B到C 长度为3,那么开车从 A经过 B到C 需要上交的过路费为 3。
        佳佳是个做生意的人,需要经常开车从任意一个城市到另外一个城市,因此他需要频繁地上交过路费,由于忙于做生意,所以他无时间来寻找交过路费最低的行驶路线。然而, 当他交的过路费越多他的心情就变得越糟糕。 作为秘书的你,需要每次根据老板的起止城市,提供给他从开始城市到达目的城市,最少需要上交多少过路费。

      这道题的数据范围比较大,n<=10^5,q<=10^4

      所以解决每一个询问的时间不能太大

      我们考虑两点间的路径中边权最大值最小的路径

      突然联想到最小生成树的性质之一:整棵树中最大的边权最小

      和我们的条件有一点相似但也不大一样

      那是否两点间路径中边权最大值最小的路径一定在最小生成树中呢?

      我们先假设不成立,即树上两点u,v之间存在一条路径中的最大值d

      小于生成树上u,v之间路径上的最大值x

      然后考虑最小生成树的Kruskal过程,我们将所有的边边权从小到大加入

      那么显然,如果u,v间的所有边边权都小于x,那么在x加入之前u,v必然已经达到联通状态

      所以这种情况是不可能出现的

      

      所以任意两点间路径中最大边权最小的路径必定在整张图的最小生成树中

      这一点得证之后,对于每个询问,O(logn)的倍增查找就可以了

    program xjt1;
    const maxm = 200010;maxn = 10010;
    var n,m,i,x,y,z,e,q:longint;
        ter,next,w:array[-1..maxm]of longint;
        link,fat,dep:array[-1..maxn]of longint;
        a:array[-1..maxm]of record x,y,z:longint;end;
        dis,fa:array[-1..maxn,-1..25]of longint;
    
    function max(a,b:longint):longint;
    begin
        if a>b then exit(a) else exit(b);
    end;
    
    procedure add(x,y,z:longint);
    begin
        inc(e);ter[e]:=y;next[e]:=link[x];link[x]:=e;w[e]:=z;
        inc(e);ter[e]:=x;next[e]:=link[y];link[y]:=e;w[e]:=z;
    end;
    
    procedure qsort(L,R:longint);
    var i,j,mid:longint;
    begin
        i:=L;j:=R;mid:=a[random(R-L+1)+L].z;
        repeat
            while (i<R)and(a[i].z<mid) do inc(i);
            while (L<j)and(a[j].z>mid) do dec(j);
            if i<=j then
            begin
                a[0]:=a[i];a[i]:=a[j];a[j]:=a[0];
                inc(i);dec(j);
            end;
        until i>j;
        if i<R then qsort(i,R);
        if L<j then qsort(L,j);
    end;
    
    function getfa(x:longint):longint;
    begin
        if fat[x]=x then exit(x);
        fat[x]:=getfa(fat[x]);
        exit(fat[x]);
    end;
    
    procedure dfs(p:longint);
    var i,j:longint;
    begin
        for i:=1 to 20 do
        begin
            if dep[p]<=1 << i then break;
            fa[p][i]:=fa[fa[p][i-1]][i-1];
            dis[p][i]:=max(dis[p][i-1],dis[fa[p][i-1]][i-1])
        end;
        j:=link[p];
        while j<>0 do
        begin
            if dep[ter[j]]=0 then
            begin
                dep[ter[j]]:=dep[p]+1;
                fa[ter[j]][0]:=p;
                dis[ter[j]][0]:=w[j];
                dfs(ter[j]);
            end;
            j:=next[j];
        end;
    end;
    
    function lca(x,y:longint):longint;
    var i,tem:longint;
    begin
        if x = y then exit(0);
        lca:=0;
        if dep[x]<dep[y] then
        begin
            tem:=x;x:=y;y:=tem;
        end;
        if dep[x]>dep[y] then
        begin
            i:=trunc(ln(dep[x]-dep[y])/ln(2));
            while dep[x]>dep[y] do
            begin
                while dep[x]-dep[y]>=1 << i do
                begin
                    lca:=max(lca,dis[x][i]);
                    x:=fa[x][i];
                end;
                            dec(i);
            end;
        end;
        if x <> y then
        begin
            i:=trunc(ln(n)/ln(2));
            while fa[x][0]<>fa[y][0] do
            begin
                while fa[x][i]<>fa[y][i] do
                begin
                    lca:=max(max(lca,dis[x][i]),dis[y][i]);
                    x:=fa[x][i];y:=fa[y][i];
                end;
                dec(i);
            end;
            lca:=max(lca,dis[x][0]);
            lca:=max(lca,dis[y][0]);
        end;
    end;
    
    begin
        readln(n,m);e:=0;
        for i:=1 to m do with a[i] do
        begin
            readln(x,y,z);
        end;
        qsort(1,m);
        for i:=1 to n do fat[i]:=i;
        for i:=1 to m do
        begin
            x:=getfa(a[i].x);y:=getfa(a[i].y);
            if x<>y then
            begin
                fat[x]:=y;
                          //  writeln(a[i].z);
                add(a[i].x,a[i].y,a[i].z);
            end;
        end;
        dep[1]:=1;dfs(1);
        readln(q);
        for i:=1 to q do
        begin
            readln(x,y);
            writeln(lca(x,y));
        end;
    end.

      

  • 相关阅读:
    MySQL 批量删除相同前缀的表
    MySQL 命令登录
    MySQL 密码修改
    谷歌浏览器开发者工具截图
    VIM命令图解
    基于环境变量为多用户配置不同的JDK(win)
    Reddit: 只有独生子女才明白的事
    JSONObject与null
    SpringFramework中重定向
    XML修改节点值
  • 原文地址:https://www.cnblogs.com/mjy0724/p/4463065.html
Copyright © 2011-2022 走看看