bzoj 1023: [SHOI2008]cactus仙人掌圖
阿新 • • 發佈:2018-12-14
起了個仙人掌的名字但是它並不是仙人掌(的做法)。。。。
首先這個圖確實是個仙人掌。。。然後如果只有樹的話就可以只跑樹上最長鏈(dfs兩遍)。
然而有一些比較煩人的環。所以我們考慮把它優化掉。所以把樹上最長鏈以dp的形式實現。
dp[i]代表這個點上的最長鏈。
然後環怎麼辦呢,可以首先造一個dfs樹,然後把環的最高點作為這個環用來dp的點,
其餘的點的互相連通情況在判環的過程中進行,之後這個點的dp值就是其中一個最長鏈的值。
而環怎麼判定呢。。。用tarjan縮點的操作。。。。(其中的dp用單調佇列維護)。
#include<cstdio> #include<cmath> #include<algorithm> #include<cstring> using namespace std; int n,m; struct node { int to; int nxt; }edge[300005]; int head[100005]; int dfn[100005],low[100005],fa[100005],dp[100005],que[100005],sta[100005]; int deep; int cnt=1,ans; void init() { memset(head,-1,sizeof(head)); deep=0;cnt=1;ans=0; memset(dfn,0,sizeof(dfn)); memset(low,0,sizeof(low)); memset(fa,0,sizeof(fa)); memset(dp,0,sizeof(dp)); memset(que,0,sizeof(que)); memset(sta,0,sizeof(sta)); } void add(int from,int to) { edge[cnt].to=to; edge[cnt].nxt=head[from]; head[from]=cnt++; } void dpit(int rt,int to) { int cct=0; while(rt!=to) { sta[++cct]=dp[to]; to=fa[to]; } sta[++cct]=dp[rt]; for(int i=1;i<cct;i++) { sta[i+cct]=sta[i]; } int head=1,tail=1; que[1]=1; for(int i=2;i<=cct+cct/2;i++)//一圈半用來更新全每個點的狀態。單調佇列維護,查出最長的路徑 { while(head<=tail&&i-que[head]>cct/2)head++; ans=max(ans,sta[i]+sta[que[head]]+i-que[head]); while(head<=tail&&sta[que[tail]]+i-que[tail]<=sta[i])tail--; que[++tail]=i; } for(int i=1;i<cct;i++) { dp[rt]=max(dp[rt],sta[i]+min(i,cct-i)); } } void tarjan(int rt) { dfn[rt]=low[rt]=++deep; for(int i=head[rt];i!=-1;i=edge[i].nxt) { int to=edge[i].to; if(to==fa[rt])continue; if(!dfn[to]) { fa[to]=rt; tarjan(to); low[rt]=min(low[rt],low[to]); if(dfn[rt]<low[to])//這個點在rt的樹邊上 { ans=max(ans,dp[rt]+1+dp[to]); dp[rt]=max(dp[rt],dp[to]+1); } }else { low[rt]=min(low[rt],dfn[to]); } } for(int i=head[rt];i!=-1;i=edge[i].nxt) { int to=edge[i].to; if(fa[to]==rt||dfn[rt]>=dfn[to])continue;//這個點不是數邊上的點也不是這個點的上面(其實就是父節點)。 dpit(rt,to); } } int main() { while(scanf("%d%d",&n,&m)!=EOF) { init(); for(int i=1;i<=m;i++) { int k,las=0;scanf("%d",&k); for(int j=1;j<=k;j++) { int x;scanf("%d",&x); if(!las) { las=x;continue; } add(las,x);add(x,las); las=x; } } tarjan(1); printf("%d\n",ans); } return 0; }