研究了一下仙人掌
首先,仙人掌虽然不是树,但却有很强的树的既视感
如果把每个环都看做一个点,那么他就是一棵树
当然这不能直接缩环,因为环和环可以有一个交点
如果是树,求直径都会做,令f[i]表示i到子树的最长距离然后弄一弄
但现在是树套环,怎么弄?
我们先根据dfs时间戳的思想,dfs下去,构成了一棵dfs树
我们的思想是先处理桥(树边),再处理环
这时候f[i]表示i在dfs树上i到子树的最长距离
dfs到i时,我们先用树形dp的思想求出不考虑环的f[i]
然后再把环拉出来一个个考虑,显然环上点j的f[j]除了和环上另一个点组成的路径对ans直接影响外
只会通过对最高点(时间戳最小的点)i的f[i]的影响来影响其他非以i为根的子树上的点
所以我们用环上的点来更新f[i]即可
再考虑环上两点路径对ans直接影响,枚举点j,显然可以得到
显然可以得到ans=max(ans,f[j]+max(f[k]+dis(j,k)));
我们对环上的点按照dfs树上的深度由小到大编号,t是环上点总数
可以得到dis(j,k)=min(k-j,t-k+j-i+1) (k>j)
考虑到环上两点间距离有两种情况,对此我们可以把环复制一遍然后做单调队列即可
最后,显然所有更新都是先更新ans再更新f[i],
1 {$m 1000000} 2 type node=record 3 po,next:longint; 4 end; 5 6 var a,q:array[0..100010] of longint; 7 fa,low,dfn,f,p,d:array[0..50010] of longint; 8 e:array[0..2000010] of node; 9 j,s,ans,h,len,i,n,m,x,y:longint; 10 11 function min(a,b:longint):longint; 12 begin 13 if a>b then exit(b) else exit(a); 14 end; 15 16 function max(a,b:longint):longint; 17 begin 18 if a>b then exit(a) else exit(b); 19 end; 20 21 procedure add(x,y:longint); 22 begin 23 inc(len); 24 e[len].po:=y; 25 e[len].next:=p[x]; 26 p[x]:=len; 27 end; 28 29 procedure dp(x,y:longint); 30 var t,h,r,i,p:longint; 31 begin 32 t:=d[y]-d[x]+1; //环上点的数目 33 h:=1; 34 r:=1; 35 p:=y; 36 for i:=t downto 1 do 37 begin 38 a[i]:=f[p]; 39 a[i+t]:=a[i]; //复制一遍,把两点间距离转化为编号差 40 p:=fa[p]; 41 end; 42 q[1]:=1; //维护单调减的双端队列 43 for i:=2 to t+t div 2 do 44 begin 45 while (h<=r) and (q[h]<i-t div 2) do inc(h); //队头的点和当前点的距离已经不是最短距离 46 ans:=max(ans,a[q[h]]+a[i]+i-q[h]); 47 while (h<=r) and (a[q[r]]-q[r]<=a[i]-i) do dec(r); 48 inc(r); 49 q[r]:=i; 50 end; 51 for i:=2 to t do 52 f[x]:=max(f[x],a[i]+min(i-1,t-i+1)); 53 end; 54 55 procedure tarjan(x:longint); 56 var i,y:longint; 57 begin 58 inc(h); 59 dfn[x]:=h; 60 low[x]:=h; 61 i:=p[x]; 62 while i<>0 do 63 begin 64 y:=e[i].po; 65 if fa[x]<>y then 66 begin 67 if dfn[y]=0 then 68 begin 69 fa[y]:=x; 70 d[y]:=d[x]+1; 71 tarjan(y); 72 end; 73 low[x]:=min(low[x],low[y]); 74 if dfn[x]<low[y] then //如果与x和x的祖先不构成环 75 begin 76 ans:=max(ans,f[x]+f[y]+1); 77 f[x]:=max(f[x],f[y]+1); 78 end; 79 end; 80 i:=e[i].next; 81 end; 82 i:=p[x]; 83 while i<>0 do 84 begin 85 y:=e[i].po; 86 if (fa[y]<>x) and (dfn[x]<dfn[y]) then //与x节点成环 87 dp(x,y); 88 i:=e[i].next; 89 end; 90 end; 91 92 begin 93 readln(n,m); 94 for i:=1 to m do 95 begin 96 read(s); 97 read(x); 98 for j:=2 to s do 99 begin 100 read(y); 101 add(x,y); 102 add(y,x); 103 x:=y; 104 end; 105 end; 106 tarjan(1); 107 writeln(ans); 108 end.