• 动态最小生成树讲解


      动态最小生成树是一类要求给定图,对于图的边有删除,插入,修改边权操作,满足查询MST(Minimum Spanning Tree )的问题。

      在这里我们考虑修改边的操作,删除可以看成是将边权设成INF,插入可以看做是将一条INF的边边权赋值。

      那么假设我们有q个询问,每个询问修改一条边的权值。

      对于q个询问里修改的边,我们设这个边集为Q,全集为E,那么对于E-Q中的边,做一遍MST,MST中的边集设为G,那么对于E-Q-G中的边,不论询问怎么改变,这些边都不会在MST中,所以我们可以删除这些边,这时全集E不包括刚才删除的边,全集中的边的数量变成了n+q,n为MST中必要的边,q为询问中的边。之后将Q中的边的边权都赋值为-ING,这时做一遍MST,如果E-Q的边在MST中,这时代表就算修改的边最小时这些边也要选,也就是这些边是保证MST连通性的必要的边,这些边我们也没有必要考虑,因为必须要选,所以将这条边连接的两个点合并成一个点,可以用并查集维护。那么这些操作之后,我们将边的规模变成了q的,点的规模变成了q的。那么我求出来询问包括1-q的情况了,在剩下的这张图(规模变小了)上,将询问的范围变成1-q>>1和q<<1-q,再递归的做下去,因为询问的不断地变小,每次都会有更多的边被缩掉(在第二次做MST时可以缩掉的边),每次边的规模都变成了q/2^dep,这样一共会有log2q层,每层做MST是qlog2q的,那么总的时间复杂度就是q(log2q,我们递归的时候不用每次都排序,可以保存原来有序的边集,所以可以去掉一个log2q,这样时间复杂度就变成了qlog2q。

      练习题,bzoj 2001 http://61.187.179.132/JudgeOnline/problem.php?id=2001

    /**************************************************************
        Problem: 2001
        User: BLADEVIL
        Language: Pascal
        Result: Accepted
        Time:14456 ms
        Memory:37024 kb
    ****************************************************************/
     
    //By BLADEVIL
    type
        node                            =record
        cnt                             :longint;
        a,b                             :array[1..250000]of longint;
        end;
         
    var
        e                               :array[1..18] of node;
        fa                              :array[1..20000]of longint;
        x, y, data, tdata               :array[0..50000]of longint;
        num, cha, ord, opt              :array[0..50000]of longint;
        i , n, m, q                     :longint;
        ans                             :int64;
         
    procedure swap(var a,b:longint);
    var
        t                               :longint;
    begin
        t:=a;
        a:=b;
        b:=t;
    end;
     
    procedure qsort(left,right:longint);
    var
        i, j, bj                        :longint;
    begin
        i:=left;
        j:=right;
        bj:=data[ord[(i+j) shr 1]];
        while i<=j do
        begin
            while data[ord[i]]<bj do inc(i);
            while data[ord[j]]>bj do dec(j);
            if i<=j then
            begin
                swap(ord[i],ord[j]);
                inc(i); dec(j);
            end;
        end;
        if j>left then qsort(left,j);
        if i<right then qsort(i,right);
    end;
     
    procedure work(dep,left,right:longint);
    var
        i, tm, tcnt                     :longint;
        tans                            :int64;
     
    function getfather(a:longint):longint;
    var
        tmp                             :longint;
    begin
        if fa[a]=a then exit(a);
        tmp:=a;
        while fa[tmp]<>tmp do tmp:=fa[tmp];
        while fa[a]<>tmp do
        begin
            inc(e[dep].cnt);
            e[dep].a[e[dep].cnt]:=a;
            e[dep].b[e[dep].cnt]:=fa[a];
            fa[a]:=tmp;
            a:=e[dep].b[e[dep].cnt];
        end;
        exit(tmp);
    end;
     
    procedure combine(a,b:longint);
    begin
        a:=getfather(a);
        b:=getfather(b);
        inc(e[dep].cnt);
        e[dep].a[e[dep].cnt]:=a;
        e[dep].b[e[dep].cnt]:=fa[a];
        fa[a]:=b;
    end;
     
    procedure recover(a:longint);
    begin
        while e[dep].cnt<>a do
        begin
            fa[e[dep].a[e[dep].cnt]]:=e[dep].b[e[dep].cnt];
            dec(e[dep].cnt);
        end;
    end;
     
    begin
        tans:=ans;
        e[dep].cnt:=0;
        if left=right then
        begin
            data[num[left]]:=cha[left];
            tdata[num[left]]:=cha[left];
            qsort(1,m);
            for i:=1 to m do
            if getfather(x[ord[i]])<>getfather(y[ord[i]]) then
            begin
                combine(x[ord[i]],y[ord[i]]);
                ans:=ans+data[ord[i]];
            end;
            writeln(ans);
            recover(0);
            ans:=tans;
            exit;
        end;
        tm:=m;
        for i:=left to right do
            data[num[i]]:=-maxlongint;
        qsort(1,m);
        opt[0]:=0;
        for i:=1 to m do
            if getfather(x[ord[i]])<>getfather(y[ord[i]]) then
            begin
                combine(x[ord[i]],y[ord[i]]);
                if data[ord[i]]<>-maxlongint then
                begin
                    inc(opt[0]);
                    opt[opt[0]]:=ord[i];
                end;
            end;
        recover(0);
        for i:=1 to opt[0] do
        begin
            combine(x[opt[i]],y[opt[i]]);
            ans:=ans+data[opt[i]];
        end;
        tcnt:=e[dep].cnt;
        for i:=left to right do
            data[num[i]]:=maxlongint;
        qsort(1,m);
        opt[0]:=0;
        for i:=1 to m do
            if getfather(x[ord[i]])<>getfather(y[ord[i]]) then
                combine(x[ord[i]],y[ord[i]]) else
                    if data[ord[i]]<>maxlongint then
                    begin
                        inc(opt[0]);
                        opt[opt[0]]:=i;
                    end;
        for i:=opt[0] downto 1 do
        begin
            swap(ord[opt[i]],ord[m]);
            dec(m);
        end;
        recover(tcnt);
        for i:=left to right do
            data[num[i]]:=tdata[num[i]];
        work(dep+1,left,(left+right) shr 1);
        work(dep+1,(left+right) shr 1 +1,right);
        m:=tm;
        ans:=tans;
        recover(0);
    end;
     
    begin
        readln(n,m,q);
        for i:=1 to n do
            fa[i]:=i;
        for i:=1 to m do
        begin
            readln(x[i],y[i],data[i]);
            tdata[i]:=data[i];
            ord[i]:=i;
        end;
        for i:=1 to q do
            readln(num[i],cha[i]);
        work(1,1,q);
    end.
  • 相关阅读:
    node
    ionic
    关于websocket和ajax无刷新
    HTML图片热区
    npm -D -S -g -i 以及安装技巧
    es6 webpack转es5
    es6
    es6
    ssh tunnel
    vim上次和下次光标位置
  • 原文地址:https://www.cnblogs.com/BLADEVIL/p/3512644.html
Copyright © 2020-2023  润新知