研究了一下仙人掌
首先,仙人掌虽然不是树,但却有很强的树的既视感
如果把每个环都看做一个点,那么他就是一棵树
当然这不能直接缩环,因为环和环可以有一个交点
如果是树,求直径都会做,令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.
View Code

 

posted on 2015-02-06 11:41  acphile  阅读(172)  评论(0编辑  收藏  举报