bzoj 3631 树链剖分+差分

题意:n个节点的树,给出访问顺序,每经过一个点该点权值加1(x->y->z,y只需要加一次),初始为0.求最后每个点经过总次数

显然树剖裸题

区间加1,单点查询,所以完全没有必要写线段树,一开始naive的想用差分的树状数组代替线段树,后来一想都差分了还树状数组个什么鬼,直接差分一下,然后算一下前缀和即可

如果当前点是所有访问的起点,直接输出sum[i],其他点均-1

var
        n,l,tot,x,y     :longint;
        i               :longint;
        a,sum           :array[0..300010] of longint;
        last            :array[0..300010] of longint;
        pre,other       :array[0..600010] of longint;
        vis             :array[0..300010] of boolean;
        d,top,num,father:array[0..300010] of longint;
        max_son,size    :array[0..300010] of longint;

procedure swap(var a,b:longint);
var
        c:longint;
begin
   c:=a; a:=b; b:=c;
end;

procedure connect(x,y:longint);
begin
   inc(l);
   pre[l]:=last[x];
   last[x]:=l;
   other[l]:=y;
end;

procedure dfs(x:longint);
var
        p,q:longint;
begin
   size[x]:=1;
   vis[x]:=true;
   q:=last[x];
   while (q<>0) do
   begin
      p:=other[q];
      if not vis[p] then
      begin
         father[p]:=x;
         dfs(p);
         inc(size[x],size[p]);
         if size[p]>size[max_son[x]] then max_son[x]:=p;
      end;
      q:=pre[q];
   end;
end;

procedure make(x,t,depth:longint);
var
        p,q:longint;
begin
   inc(tot);
   num[x]:=tot;
   d[x]:=depth;
   top[x]:=t;
   //
   if (max_son[x]<>0) and not vis[max_son[x]] then
   begin
      vis[max_son[x]]:=true;
      make(max_son[x],t,depth);
   end;
   q:=last[x];
   while (q<>0) do
   begin
      p:=other[q];
      if (p<>max_son[x]) and not vis[p] then
      begin
         vis[p]:=true;
         make(p,p,depth+1);
      end;
      q:=pre[q];
   end;
end;

procedure change(x,y:longint);
begin
   inc(sum[x]);
   dec(sum[y+1]);
end;

procedure work(x,y:longint);
begin
   if d[x]>d[y] then swap(x,y);
   while d[x]top[y] do
   begin
      change(num[top[x]],num[x]);
      change(num[top[y]],num[y]);
      x:=father[top[x]];
      y:=father[top[y]];
   end;
   if num[x]
——by Eirlys

bzoj 3631 树链剖分+差分_第1张图片

你可能感兴趣的:(bzoj,树链剖分)