1. 程式人生 > >2018.10.29 bzoj1023: [SHOI2008]cactus仙人掌圖(仙人掌+單調佇列優化dp)

2018.10.29 bzoj1023: [SHOI2008]cactus仙人掌圖(仙人掌+單調佇列優化dp)

傳送門
求仙人掌的直徑。
感覺不是很難。


分點在環上面和不在環上分類討論。
不在環上直接樹形 d p dp
然後如果在環上討論一波。
首先對環的祖先有貢獻的只有環上 d f s

dfs 序最小的點。
對答案有貢獻的則是環上的任意兩個點。
對於環上任意兩點 ( i , j ) (i,j)

A n s = m a x ( A n
s , f [ i ] + f [ j ] + d i s t ( i , j ) ) Ans=max(Ans,f[i]+f[j]+dist(i,j))
其中 d i s t dist 指的是較短的距離。
假設 i > j i>j 那麼 f [ i ] + f [ j ] + i j f[i]+f[j]+i-j 這個式子可以用單調佇列優化。
然後均攤下來每次複雜度是當前環長度。
因此總複雜度 O ( n ) O(n)
程式碼:

#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;
}