bzoj1023: [SHOI2008]cactus仙人掌图

题解可以看这篇,写的很清楚……
http://z55250825.blog.163.com/blog/static/150230809201412793151890/

然后我的单调队列写出来竟然和他不一样……
max(f[i]+f[j]+j-i)j属于[i+1,i+sum/2]的话,对于j的话,不就是max(f[i]-i)+f[j]+j,维护f[i]-i递增不就行了么?

那么说一下这种环套树的基本写法……

首先是建图
然后跑tarjan,跑得时候要记录下某个点的父亲,然后如果某个点x的某个儿子son存在dfn[x]<low[too],那么明显x-son就是一个桥……这一部分可以看成是树dp中某个节点和儿子。然后某个点跑完tarjan后再找出它所有fa[son]<>x且dfn[x]<dfn[too],这时就是以x到too再到x的环,这时候就跑个循环dp,只不过要注意那个x取too就不能取,too取x就不能取,两遍for解决……

也就是树当树,环当环处理啦……

 

type
  arr=record
    toward,next:longint;
  end;
 
const
  maxm=3000000;
  maxn=300000;
 
var
  edge:array[0..maxm]of arr;
  first,num,a,f,p,dfn,low,dep,fa:array[0..maxn]of longint;
  n,m,time,tot,ans:longint;
 
 
function max(x,y:longint):longint;
begin
  if x<y then exit(y);
  exit(x);
end;
 
function min(x,y:longint):longint;
begin
  if x<y then exit(x);
  exit(y);
end;
 
procedure addedge(i,j:longint);
begin
  inc(tot);
  edge[tot].toward:=j;
  edge[tot].next:=first[i];
  first[i]:=tot;
end;
 
procedure dp(x,root:longint);
var
  sum,head,tail,i:longint;
begin
  sum:=dep[x]-dep[root]+1;
  i:=x;
  while sum>0 do begin
    num[sum]:=f[x];
    x:=fa[x];
    dec(sum);
  end;
  x:=i;
  sum:=dep[x]-dep[root]+1;
  for i:=1 to sum do
    num[i+sum]:=num[i];
  head:=1;
  tail:=1;
  p[1]:=1;
  for i:=2 to sum<<1 do begin
    while (head<=tail) and (p[head]+sum>>1<i) do inc(head);
    ans:=max(ans,num[p[head]]-p[head]+num[i]+i);
    while (head<=tail) and (num[p[tail]]-p[tail]<num[i]-i) do dec(tail);
    inc(tail);
    p[tail]:=i;
  end;
  for i:=2 to sum do
    f[root]:=max(f[root],min(i-1,sum-i+1)+num[i]);
end;
 
procedure tarjan(x:longint);
var
  i,too:longint;
begin
  inc(time);
  dfn[x]:=time;
  low[x]:=time;
  i:=first[x];
  while i>0 do begin
    too:=edge[i].toward;
    if too<>fa[x] then begin
      if dfn[too]=0 then begin
        dep[too]:=dep[x]+1;
        fa[too]:=x;
        tarjan(too);
        if low[too]<low[x] then low[x]:=low[too];
      end
      else
        if dfn[too]<low[x] then low[x]:=dfn[too];
      if dfn[x]<low[too] then begin
        ans:=max(ans,f[x]+f[too]+1);
        f[x]:=max(f[x],f[too]+1);
      end;
    end;
    i:=edge[i].next;
  end;
  i:=first[x];
  while i>0 do begin
    too:=edge[i].toward;
    if (fa[too]<>x)  and (dfn[x]<dfn[too]) then dp(too,x);
    i:=edge[i].next;
  end;
end;
 
procedure into;
var
  i,j,k:longint;
begin
  readln(n,m);
  for i:=1 to m do begin
    read(k,a[1]);
    for j:=2 to k do begin
      read(a[j]);
      addedge(a[j],a[j-1]);
      addedge(a[j-1],a[j]);
    end;
  end;
end;
 
procedure work;
begin
  time:=0;
  ans:=0;
  dep[1]:=1;
  tarjan(1);
  writeln(ans);
end;
 
begin
  into;
  work;
end.
View Code

 (有时间再搞搞丧心病狂的动态仙人掌)

posted @ 2014-12-23 19:13  Macaulish  阅读(203)  评论(0编辑  收藏  举报