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.

 

posted on 2013-11-20 14:34  BLADEVIL  阅读(427)  评论(0编辑  收藏  举报