bzoj1040 内向树DP

2013-11-17 08:52

原题传送门http://www.lydsy.com/JudgeOnline/problem.php?id=1040

N个骑士,每个人有一个仇人,那么,每个骑士只有一个后继,将他和他憎恨的人连边,就组成了

一颗内向树,内向树可以看成环儿上挂一堆树,那么我们对于每个环儿上的点,求出以该点为根节点

的子树,取不取该根节点的价值(树P就好了,类似于没有上司的舞会),然后我们得到了一个环儿

知道每个点取不取的价值,求最大价值,那么我们可以破环为链,固定第一个取不取,然后DP,如果

第一个取,那么答案就是c[tot,0],不取的话答案就是max(c[tot,1],c[tot,0]),tot为环最后一个节点

然后取两个的最大值就好了,因为可能图有多个块,所以累加每个块的最大值就是ans。

Ps:我知道我的代码写的长。。。。风格。。。

//By BLADEVIL

var

    n                           :int64;

    pre, last, other            :array[0..1000010] of int64;

    l                           :int64;

    low, dfn, stack, key        :array[0..1000010] of int64;

    flag                        :array[0..1000010] of boolean;

    time                        :int64;

    que                         :array[0..1000010] of int64;

    fuck                        :int64;

    tot                         :int64;

    v                           :array[0..1000010] of int64;

    w, c                        :array[0..1000010,0..2] of int64;

    finish                      :array[0..1000010] of boolean;

    ans                         :int64;

     

function min(a,b:int64):int64;

begin

    if a>b then min:=b else min:=a;

end;

     

function max(a,b:int64):int64;

begin

    if a>b then max:=a else max:=b;

end;

 

procedure connect(x,y:int64);

begin

    inc(l);

    pre[l]:=last[x];

    last[x]:=l;

    other[l]:=y;

end;

 

procedure init;

var

    i                           :longint;

    y                           :int64;

begin

    read(n);

    for i:=1 to n do

    begin

        read(v[i],y);

        connect(y,i);

    end;

end;

 

procedure dfs(x:int64);

var

    p, q                        :int64;

    cur                         :int64;

begin

    inc(time);

    dfn[x]:=time;

    low[x]:=time;

    inc(tot);

    stack[tot]:=x;

    flag[x]:=true;

 

    q:=last[x];

    while q<>0 do

    begin

        p:=other[q];

        if dfn[p]=0 then

        begin

            dfs(p);

            low[x]:=min(low[x],low[p]);

        end else

        if flag[p] then low[x]:=min(low[x],dfn[p]);

        q:=pre[q];

    end;

     

    cur:=-1;

    if dfn[x]=low[x] then

    begin

        while cur<>x do

        begin

            cur:=stack[tot];

            dec(tot);

            flag[cur]:=false;

            key[cur]:=x;

        end;

    end;

end;

 

procedure doit(x:int64);

var

    q, p                        :int64;

    h, t                        :int64;

    cur                         :int64;

    i                           :longint;

    now                         :int64;

     

begin

    t:=1; h:=0;

    que[1]:=x; q:=last[x];

    while t<>h do

    begin

        inc(h);

        cur:=que[h];

        q:=last[cur];

        while q<>0 do

        begin

            p:=other[q];

            if key[p]=fuck then

            begin

                q:=pre[q];

                continue;

            end;

            inc(t);

            que[t]:=p;

            q:=pre[q];

        end;

    end;

    for i:=t downto 1 do

    begin

        now:=que[i];

        q:=last[now];

        w[now,1]:=v[now];

        if q=0 then w[now,1]:=v[now];

        while q<>0 do

        begin

            p:=other[q];

            if key[p]<>fuck then

            begin

                w[now,0]:=w[now,0]+max(w[p,0],w[p,1]);

                w[now,1]:=w[now,1]+w[p,0];

            end;

            q:=pre[q];

        end;

    end;

end;

 

procedure main;

var

    i, j                        :longint;

    q, p                        :int64;

    f                           :boolean;

    now                         :int64;

     

begin

    for i:=1 to n do if dfn[i]=0 then dfs(i);

    for i:=1 to n do if (low[i]<>dfn[i]) and (not finish[key[i]]) then

    begin

        fuck:=key[i]; finish[fuck]:=true;

        for j:=1 to n do if key[j]=fuck then doit(j);

        fillchar(flag,sizeof(flag),false);

        for j:=1 to n do if key[j]=fuck then break;

        fillchar(que,sizeof(que),0);

        que[1]:=j; tot:=1;

        f:=false;

        while true do

        begin

            q:=last[que[tot]];

            while q<>0 do

            begin

                p:=other[q];

                if flag[p] then

                begin

                    f:=true;

                    break;

                end;

                if key[p]=fuck then

                begin

                    inc(tot);

                    que[tot]:=p;

                    flag[p]:=true;

                end;

                q:=pre[q];

            end;

            if f then break;

        end;

        fillchar(c,sizeof(c),0);

        c[que[1],1]:=-maxlongint; c[que[1],0]:=w[que[1],0];

        for j:=2 to tot-1 do

        begin

            c[que[j],0]:=max(c[que[j-1],0],c[que[j-1],1])+w[que[j],0];

            c[que[j],1]:=c[que[j-1],0]+w[que[j],1];

        end;

        now:=-maxlongint;

        for j:=2 to tot-1 do now:=max(now,max(c[que[j],0],c[que[j],1]));

        fillchar(c,sizeof(c),0);

        c[que[1],1]:=w[que[1],1]; c[que[1],0]:=-maxlongint;

        for j:=2 to tot-1 do

        begin

            c[que[j],0]:=max(c[que[j-1],0],c[que[j-1],1])+w[que[j],0];

            c[que[j],1]:=c[que[j-1],0]+w[que[j],1];

        end;

        for j:=2 to tot-2 do now:=max(now,max(c[que[j],0],c[que[j],1]));

        now:=max(now,c[que[tot-1],0]);

        inc(ans,now);

    end;

    writeln(ans);

end;

 

begin

    init;

    main;

end.

 

你可能感兴趣的:(ZOJ)