[BZOJ1791][IOI2008] Island 基环外向树+DP
2017-04-27 08:04
316 查看
题中说每个点连出一条边,所以图应该是很多个基环+外向树。
对于每一个联通块,一条最长路径可能在某一棵子树中,也可能两棵子树各一部分加上中间一段环的路径。所以先找出它的环,对每棵树先进行树型DP,记到根最长距离为g[i]。然后把环展开(1-2-3的环展开成1-2-3-1-2),维护一个距离前缀和dis[i],这就是一个决策区间单调移动的DP了,方程为f[i]=max{g[j]-dis[j]}+dis[i] (i-j+1<=环长度),然后单调队列维护g[j]-dis[j]即可。
最终答案不一定是f[i]的最大值,也有可能在某一棵子树,所以树型DP的时候也要统计答案。
然后这题输入格式好,对第i行输入,i—>nt[i]的边,把i->nt[i]看成正向,nt[i]->i看成反向(正向的用nt数组记,反向的加到邻接表里),找环的时候只要随便找一点走正向边,树型dp的时候都是在反向边上dp,巧妙吧。。。
这题好像要手写栈,不然OJ上会RE,懒得写了。。。
(话说我本地测RE两个点,交上去OLE是什么鬼
代码:
对于每一个联通块,一条最长路径可能在某一棵子树中,也可能两棵子树各一部分加上中间一段环的路径。所以先找出它的环,对每棵树先进行树型DP,记到根最长距离为g[i]。然后把环展开(1-2-3的环展开成1-2-3-1-2),维护一个距离前缀和dis[i],这就是一个决策区间单调移动的DP了,方程为f[i]=max{g[j]-dis[j]}+dis[i] (i-j+1<=环长度),然后单调队列维护g[j]-dis[j]即可。
最终答案不一定是f[i]的最大值,也有可能在某一棵子树,所以树型DP的时候也要统计答案。
然后这题输入格式好,对第i行输入,i—>nt[i]的边,把i->nt[i]看成正向,nt[i]->i看成反向(正向的用nt数组记,反向的加到邻接表里),找环的时候只要随便找一点走正向边,树型dp的时候都是在反向边上dp,巧妙吧。。。
这题好像要手写栈,不然OJ上会RE,懒得写了。。。
(话说我本地测RE两个点,交上去OLE是什么鬼
代码:
type edge=^edgenode; edgenode=record t,w:longint; next:edge; end; node=record t:longint; w:int64; end; const maxn=1000100; var n,i,j,x,y,num,top,oncir:longint; ans,all:int64; con:array[0..maxn]of edge; visit,cir:array[0..maxn]of boolean; huan:array[0..maxn]of longint; nt:array[0..maxn]of node; g,dis:array[0..2*maxn]of int64; dl:array[0..2*maxn]of node; procedure ins(x,y,w:longint); var p:edge; begin new(p); p^.t:=y; p^.w:=w; p^.next:=con[x]; con[x]:=p; end; function max(x,y:int64):int64; begin if x>y then exit(x) else exit(y); end; procedure findcir(v:longint); var p:edge; begin visit[v]:=true; if visit[nt[v].t]=false then findcir(nt[v].t) else oncir:=nt[v].t; if oncir>0 then begin inc(top); huan[top]:=v; cir[v]:=true; end; if oncir=v then oncir:=0; visit[v]:=false; end; function dfs(v:longint):int64; var p:edge; now,o:int64; begin p:=con[v]; dfs:=0; now:=0; visit[v]:=true; while p<>nil do begin if cir[p^.t]=false then begin o:=dfs(p^.t)+p^.w; dfs:=max(dfs,o); ans:=max(ans,o+now); now:=max(now,o); end; p:=p^.next; end; end; procedure dp; var i,j,head,tail:longint; begin head:=1; tail:=0; for i:=1 to 2*top-1 do begin while (head<=tail)and(dl[head].t<=i-top) do inc(head); if i>=top then ans:=max(ans,dl[head].w+g[i]+dis[i]); while (head<=tail)and(g[i]-dis[i]>=dl[tail].w) do dec(tail); inc(tail); dl[tail].t:=i; dl[tail].w:=g[i]-dis[i]; end; end; begin readln(n); for i:=1 to n do begin readln(x,y); nt[i].t:=x; nt[i].w:=y; ins(x,i,y); end; fillchar(visit,sizeof(visit),false); fillchar(cir,sizeof(cir),false); for i:=1 to n do if visit[i]=false then begin oncir:=0; top:=0; ans:=0; findcir(i); for j:=1 to top do g[j]:=dfs(huan[j]); for j:=1 to top-1 do begin g[j+top]:=g[j]; huan[j+top]:=huan[j]; end; dis[1]:=0; for j:=2 to 2*top-1 do dis[j]:=dis[j-1]+nt[huan[j]].w; dp; all:=all+ans; end; write(all); end.
相关文章推荐
- 【BZOJ1791】【IOI2008】【基环树】island(status第一速度)
- 【BZOJ1791】【IOI2008】【基环树】island(status速度第一)
- bzoj 1791: [Ioi2008]Island 岛屿【基环树+单调队列优化dp】
- 树形dp 基环树直径 bzoj1791 ioi2008island
- 【BZOJ 1791】 [Ioi2008]Island 岛屿
- 【BZOJ 1791】 [Ioi2008]Island 岛屿
- bzoj千题计划114:bzoj1791: [Ioi2008]Island 岛屿
- [环套树 单调队列DP] BZOJ 1791 [Ioi2008]Island 岛屿
- [BZOJ1791][IOI2008]Island岛屿(环套树DP)
- BZOJ 1791 [Ioi2008] Island 岛屿
- bzoj 1791: [Ioi2008]Island 岛屿
- BZOJ1795 : [Ioi2008]Pyramid Base 金字塔地基
- 【bzoj 3049】[Usaco2013 Jan]Island Travels(状压dp)
- [基环外向树+树形DP]BZOJ 1040—— [ZJOI2008]骑士
- BZOJ 1794 Ioi2008 Linear Garden
- [bzoj1040][ZJOI2008]骑士_树形dp_基环树_并查集
- bzoj 1791 DP
- [BZOJ3242][NOI2013]快餐店-基环树-动态规划
- 【bzoj1040】骑士 基环外向树 树规
- bzoj 2791 [Poi2012]Rendezvous 基环森林