[bzoj1023]仙人掌图
好神啊。。。完全不会。。。
树上DP+环上DP
如果当前节点是割点,那么就tarjan下去然后树上dp一下,f[x]记录一下x的最长链,然后在更新的时候更新答案
如果是一个环,那么就用bzoj1040那样的基环树类似的套路,把环搞成一个区间,然后跑一下单调队列
由于环比较特殊,另环最上面的点为root,然后更新f[root]就行
各种乱搞Orz
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstring> 5 #include <cstdlib> 6 #include <queue> 7 using namespace std; 8 9 const int N=60000; 10 int h[N],to[20000005],r[20000005]; 11 void add(int u,int v){ 12 static int tot=0; 13 to[++tot]=v; 14 r[tot]=h[u]; 15 h[u]=tot; 16 } 17 18 int n,m,ans,fa[N],a[200000],dfn[N],low[N],f[N],deep[N],q[200000]; 19 20 void dp(int root,int x){ 21 int tot=deep[x]-deep[root]+1; 22 for(int i=x;i!=root;i=fa[i]) 23 a[tot--]=f[i]; 24 a[tot]=f[root]; 25 tot=deep[x]-deep[root]+1; 26 for(int i=1;i<=tot;i++)a[tot+i]=a[i]; 27 int l,r; 28 q[l=r=1]=1; 29 for(int i=2;i<=2*tot;i++){ 30 while(l<=r&&i-q[l]>tot/2)l++; 31 ans=max(ans,a[i]+a[q[l]]+i-q[l]); 32 while(l<=r&&a[q[r]]-q[r]<=a[i]-i)r--; 33 q[++r]=i; 34 } 35 for(int i=2;i<=tot;i++)f[root]=max(f[root],a[i]+min(i-1,tot-i+1)); 36 } 37 38 void dfs(int x){ 39 static int tot=0; 40 low[x]=dfn[x]=++tot; 41 for(int i=h[x];i;i=r[i]){ 42 if(to[i]==fa[x])continue; 43 if(!dfn[to[i]]){ 44 fa[to[i]]=x; 45 deep[to[i]]=deep[x]+1; 46 dfs(to[i]); 47 low[x]=min(low[x],low[to[i]]); 48 }else low[x]=min(low[x],dfn[to[i]]); 49 if(dfn[x]<low[to[i]]){ 50 ans=max(ans,f[to[i]]+1+f[x]); 51 f[x]=max(f[x],f[to[i]]+1); 52 } 53 } 54 for(int i=h[x];i;i=r[i]) 55 if(fa[to[i]]!=x&&dfn[x]<dfn[to[i]]) 56 dp(x,to[i]); 57 } 58 59 int main(){ 60 scanf("%d%d",&n,&m); 61 for(int i=1;i<=m;i++){ 62 int k,l,t;scanf("%d%d",&k,&l); 63 for(int i=1;i<k;i++){ 64 scanf("%d",&t); 65 add(l,t),add(t,l); 66 l=t; 67 } 68 } 69 dfs(1); 70 printf("%d\n",ans); 71 }