1. 程式人生 > >bzoj 1023 [SHOI2008]cactus仙人掌圖 ( poj 3567 Cactus Reloaded )——仙人掌直徑模板

bzoj 1023 [SHOI2008]cactus仙人掌圖 ( poj 3567 Cactus Reloaded )——仙人掌直徑模板

tarjan main ati spa space ext sca geo clu

題目:https://www.lydsy.com/JudgeOnline/problem.php?id=1023

   http://poj.org/problem?id=3567

因為lyd在講課,所以有了lyd的模板。感覺人家寫得好好呀!於是學習(抄)了一下。可以記一記。

反正各種優美。那個dp斷環成鏈的地方那麽流暢自然!tarjan裏的那些 if 條件那麽美!

不過十分不明白為什麽邊要開成4倍的。開成2倍的真的會RE。怎麽分析仙人掌的邊數?

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace
std; const int N=5e4+5; int n,m,hd[N],xnt,dfn[N],low[N],tim,fa[N],f[N],a[N<<1],q[N<<1],ans;//N<<1!! struct Ed{ int nxt,to;Ed(int n=0,int t=0):nxt(n),to(t) {} }ed[N<<2];//<<2(?) void add(int x,int y) { ed[++xnt]=Ed(hd[x],y);hd[x]=xnt; } void dp(int x,int y) { int m,i,l,r,p;
for(m=0;y!=x;y=fa[y])a[++m]=f[y];// a is value for(a[++m]=f[x],i=1;i<m;i++)a[m+i]=a[i];// 2*m-1 is enough l=r=q[1]=1;p=(m>>1); for(i=2;i<=m+p;i++) { while(l<=r&&i-q[l]>p)l++; ans=max(ans,a[q[l]]+a[i]+i-q[l]);// a[],not f already(i is pos on a[]) while(l<=r&&a[i]>=a[q[r]]+i-q[r])r--; q[
++r]=i; } for(int i=1;i<m;i++)f[x]=max(f[x],a[i]+min(i,m-i)); } void tarjan(int cr) { dfn[cr]=low[cr]=++tim; for(int i=hd[cr],v;i;i=ed[i].nxt) if((v=ed[i].to)!=fa[cr])//! if(!dfn[v]) { fa[v]=cr;tarjan(v); low[cr]=min(low[cr],low[v]); if(low[v]>dfn[cr]) { ans=max(ans,f[cr]+f[v]+1); f[cr]=max(f[cr],f[v]+1); } } else low[cr]=min(low[cr],dfn[v]); for(int i=hd[cr],v;i;i=ed[i].nxt) if(fa[v=ed[i].to]!=cr&&dfn[v]>dfn[cr])dp(cr,v); } int main() { scanf("%d%d",&n,&m);int k,x,y; for(int i=1;i<=m;i++) { scanf("%d%d",&k,&x); for(int j=1;j<k;j++) { scanf("%d",&y); add(x,y);add(y,x);x=y; } } tarjan(1); printf("%d",ans); return 0; }

bzoj 1023 [SHOI2008]cactus仙人掌圖 ( poj 3567 Cactus Reloaded )——仙人掌直徑模板