论环形dp的重要!
其实这个环比较简单,稍微分析一下就知道,
这是一个简单环,并且每个联通块里只含有一个。
我觉得把处理环的关键,就是要找出环形和线形(树形)有什么区别。
如果我们从某处断开的做dp的话,转移的结果只对根节点有影响(不确定);
然后我猜测应该只要找到环上相邻两点然后断开分别以他们为根做treedp就可以了
结果真的是这样……
总感觉缺点什么……
有待进一步思考……
1 type node=record 2 point,next:longint; 3 end; 4 5 var edge:array[0..2000010] of node; 6 can:array[0..2000010] of boolean; 7 v:array[0..1000010] of boolean; 8 p,w:array[0..1000010] of longint; 9 f:array[0..1000010,0..1] of int64; 10 len,find,n,u,z,i:longint; 11 ans,res:int64; 12 13 function max(a,b:int64):int64; 14 begin 15 if a>b then exit(a) else exit(b); 16 end; 17 18 procedure add(x,y:longint); 19 begin 20 inc(len); 21 edge[len].point:=y; 22 edge[len].next:=p[x]; 23 can[len]:=true; 24 p[x]:=len; 25 end; 26 27 procedure dfs(x:longint); //找环 28 var i,y:longint; 29 begin 30 v[x]:=true; 31 i:=p[x]; 32 while i<>-1 do 33 begin 34 y:=edge[i].point; 35 if can[i] and not v[y] then 36 begin 37 can[i xor 1]:=false; //注意防止因为同一条边而回头 38 dfs(y); 39 can[i xor 1]:=true; //解除标记 40 end 41 else if can[i] and v[y] then 42 begin 43 u:=x; 44 z:=y; 45 find:=i; 46 end; 47 i:=edge[i].next; 48 end; 49 end; 50 51 procedure treedp(x:longint); 52 var i,y:longint; 53 begin 54 i:=p[x]; 55 f[x,0]:=0; 56 f[x,1]:=w[x]; 57 while i<>-1 do 58 begin 59 y:=edge[i].point; 60 if can[i] then 61 begin 62 can[i xor 1]:=false; 63 treedp(y); 64 can[i xor 1]:=true; 65 f[x,0]:=f[x,0]+max(f[y,0],f[y,1]); //基本的treedp 66 f[x,1]:=f[x,1]+f[y,0]; 67 end; 68 i:=edge[i].next; 69 end; 70 end; 71 72 procedure dp(i:longint); 73 begin 74 dfs(i); 75 can[find]:=false; //断开 76 can[find xor 1]:=false; 77 treedp(u); 78 res:=f[u,0]; 79 treedp(z); 80 ans:=ans+max(f[z,0],res); //都是不取根,这里是凭感觉写的,欢迎指教 81 end; 82 83 begin 84 len:=-1; 85 readln(n); 86 fillchar(p,sizeof(p),255); 87 for i:=1 to n do 88 begin 89 readln(w[i],z); 90 add(z,i); 91 add(i,z); 92 end; 93 for i:=1 to n do 94 if not v[i] then dp(i); 95 writeln(ans); 96 end.