2018.10.29 bzoj1023: [SHOI2008]cactus仙人掌圖(仙人掌+單調佇列優化dp)
阿新 • • 發佈:2018-10-31
傳送門
求仙人掌的直徑。
感覺不是很難。
分點在環上面和不在環上分類討論。
不在環上直接樹形
。
然後如果在環上討論一波。
首先對環的祖先有貢獻的只有環上
序最小的點。
對答案有貢獻的則是環上的任意兩個點。
對於環上任意兩點
其中
指的是較短的距離。
假設
那麼
這個式子可以用單調佇列優化。
然後均攤下來每次複雜度是當前環長度。
因此總複雜度
程式碼:
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans;
}
const int N=2e5+5,M=1e6+5;
int n,m,first[N],cnt=0,tot=0,fa[N],dep[N],f[N],dfn[N],low[N],q[N<<1],a[N<<1],hd,tl,ans=0;
struct edge{int v,next;}e[M<<1];
inline void add(int u,int v){e[++cnt].v=v,e[cnt].next=first[u],first[u]=cnt;}
inline void update(int st,int ed){
int siz=dep[ed]-dep[st]+1,lim=siz>>1,all=siz;
for(int pos=ed,i=siz;i;--i,pos=fa[pos])a[i]=pos;
memcpy(a+siz+1,a+1,sizeof(int)*lim),siz+=lim,q[hd=tl=1]=1;
for(int i=2;i<=siz;++i){
while(hd<=tl&&q[hd]<i-lim)++hd;
ans=max(ans,f[a[i]]+f[a[q[hd]]]+i-q[hd]);
while(hd<=tl&&f[a[q[tl]]]-q[tl]<=f[a[i]]-i)--tl;
q[++tl]=i;
}
for(int i=2;i<=all;++i)f[st]=max(f[st],f[a[i]]+min(i-1,all-i+1));
}
inline void tarjan(int p){
dfn[p]=low[p]=++tot;
for(int i=first[p];i;i=e[i].next){
int v=e[i].v;
if(v==fa[p])continue;
if(!dfn[v])fa[v]=p,dep[v]=dep[p]+1,tarjan(v),low[p]=min(low[p],low[v]);
else low[p]=min(low[p],dfn[v]);
if(dfn[p]<low[v])ans=max(ans,f[p]+f[v]+1),f[p]=max(f[p],f[v]+1);
}
for(int i=first[p];i;i=e[i].next){
int v=e[i].v;
if(fa[v]!=p&&dfn[p]<dfn[v])update(p,v);
}
}
int main(){
n=read(),m=read();
while(m--){
int k=read()-1,x=read(),y;
while(k--)y=read(),add(x,y),add(y,x),x=y;
}
tarjan(1),cout<<ans;
return 0;
}