动态最小生成树讲解

  动态最小生成树是一类要求给定图,对于图的边有删除,插入,修改边权操作,满足查询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.
动态最小生成树讲解

动态最小生成树讲解

上一篇:微信小程序开发,设置合法域名


下一篇:全能系统监控工具dstat