【以前的空间】树链剖分

http://www.cnblogs.com/BLADEVIL/p/3479713.html

这个大神写的特别好……难得的是还是p党(感动)

[ZJOI2008]树的统计Count

线段树只需要单点修改……

type

  arr1=record

    toward,next:longint;

  end;

  arr2=record

    left,right,max,sum:longint;

  end;

 

 

const

  mm=500000;

var

  tree:array[0..mm]of arr2;

  edge:array[0..mm]of arr1;

  first,num,value,top,hash,fa,size,maxson,dep:array[0..mm]of longint;

  chose:array[0..mm]of boolean;

  total,tot:longint;

 

function max(x,y:longint):longint;

begin

  if x<y then exit(y);

  exit(x);

end;

 

procedure swap(var x,y:longint);

var

  i:longint;

begin

  i:=x;

  x:=y;

  y:=i;

end;

 

procedure update(x:longint);

begin

  tree[x].sum:=tree[x<<1].sum+tree[x<<1+1].sum;

  tree[x].max:=max(tree[x<<1].max,tree[x<<1+1].max);

end;

 

procedure addedge(j,k:longint);

begin

  inc(total);

  edge[total].toward:=k;

  edge[total].next:=first[j];

  first[j]:=total;

end;

 

procedure dfs(x:longint);

var

  i,too:longint;

begin

  chose[x]:=false;

  i:=first[x];

  size[x]:=1;

  maxson[x]:=0;

  while i<>0 do begin

    too:=edge[i].toward;

    if chose[too] then begin

      fa[too]:=x;

      dfs(too);

      inc(size[x],size[too]);

      if size[too]>size[maxson[x]] then maxson[x]:=too;

    end;

    i:=edge[i].next;

  end;

end;

 

procedure make(x,y,depth:longint);

var

  i,too:longint;

begin

  inc(tot);

  num[x]:=tot;

  hash[tot]:=value[x];

  chose[x]:=false;

  top[x]:=y;

  dep[x]:=depth;

  if maxson[x]<>0 then make(maxson[x],y,depth);

  i:=first[x];

  while i<>0 do begin

    too:=edge[i].toward;

    if (chose[too]) and (too<>maxson[x]) then make(too,too,depth+1);

    i:=edge[i].next;

  end;

end;

 

procedure build(x,l,r:longint);

var

  mid:longint;

begin

  tree[x].left:=l;

  tree[x].right:=r;

  if l=r then begin

    tree[x].sum:=hash[l];

    tree[x].max:=hash[l];

    exit;

  end;

  mid:=(l+r)>>1;

  build(x<<1,l,mid);

  build(x<<1+1,mid+1,r);

  update(x);

end;

 

function askmax(x,ll,rr:longint):longint;

var

  mid:longint;

begin

  if (tree[x].left=ll) and (tree[x].right=rr) then exit(tree[x].max);

  mid:=(tree[x].left+tree[x].right)>>1;

  if ll>mid

    then exit(askmax(x<<1+1,ll,rr))

    else

      if rr<=mid then exit(askmax(x<<1,ll,rr))

      else exit(max(askmax(x<<1,ll,mid),askmax(x<<1+1,mid+1,rr)));

end;

 

function asksum(x,ll,rr:longint):longint;

var

  mid:longint;

begin

  if (tree[x].left=ll) and (tree[x].right=rr) then exit(tree[x].sum);

  mid:=(tree[x].left+tree[x].right)>>1;

  if ll>mid then exit(asksum(x<<1+1,ll,rr))

  else

    if rr<=mid then exit(asksum(x<<1,ll,rr))

    else exit(asksum(x<<1,ll,mid)+asksum(x<<1+1,mid+1,rr));

end;

 

procedure change(x,u,z:longint);

var

  mid:longint;

begin

  if (tree[x].left=u) and (tree[x].right=u) then begin

    tree[x].sum:=z;

    tree[x].max:=z;

    exit;

  end;

  mid:=(tree[x].left+tree[x].right)>>1;

  if u>mid then change(x<<1+1,u,z)

  else change(x<<1,u,z);

  update(x);

end;

 

procedure querymax(x,y:longint);

var

  ans:longint;

begin

  ans:=-100000000;

  if dep[x]>dep[y] then swap(x,y);

  while dep[x]<dep[y] do begin

    ans:=max(ans,askmax(1,num[top[y]],num[y]));

    y:=fa[top[y]];

  end;

  while top[x]<>top[y] do begin

    ans:=max(ans,max(askmax(1,num[top[x]],num[x]),askmax(1,num[top[y]],num[y])));

    x:=fa[top[x]];

    y:=fa[top[y]];

  end;

  x:=num[x];

  y:=num[y];

  if x>y then swap(x,y);

  ans:=max(ans,askmax(1,x,y));

  writeln(ans);

end;

 

procedure querysum(x,y:longint);

var

  ans:longint;

begin

  ans:=0;

  if dep[x]>dep[y] then swap(x,y);

  while dep[x]<dep[y] do begin

    ans:=ans+asksum(1,num[top[y]],num[y]);

    y:=fa[top[y]];

  end;

  while top[x]<>top[y] do begin

    ans:=ans+asksum(1,num[top[x]],num[x])+asksum(1,num[top[y]],num[y]);

    x:=fa[top[x]];

    y:=fa[top[y]];

  end;

  x:=num[x];

  y:=num[y];

  if x>y then swap(x,y);

  ans:=ans+asksum(1,x,y);

  writeln(ans);

end;

 

procedure into;

var

  i,j,k,n:longint;

begin

  readln(n);

  total:=0;

  tot:=0;

  fillchar(first,sizeof(first),0);

  for i:=1 to n-1 do begin

    readln(j,k);

    addedge(j,k);

    addedge(k,j);

  end;

  for i:=1 to n do read(value[i]);

  readln;

  fillchar(size,sizeof(size),0);

  fillchar(chose,sizeof(chose),true);

  dfs(1);

  fillchar(chose,sizeof(chose),true);

  make(1,1,1);

  build(1,1,n);

end;

 

 

procedure work;

var

  m,j,k:longint;

  ch:char;

begin

  readln(m);

  while m>0 do begin

    dec(m);

    read(ch);

    if ch='Q' then begin

      read(ch);

      if ch='M' then begin

        repeat

          read(ch);

        until ch=' ';

        readln(j,k);

        querymax(j,k);

      end

      else begin

        repeat

          read(ch);

        until ch=' ';

        readln(j,k);

        querysum(j,k);

      end;

    end

    else begin

      repeat

        read(ch);

      until ch=' ';

      readln(j,k);

      change(1,num[j],k);

    end;

  end;

end;

 

 

begin

  into;

  work;

  readln;

  readln;

end.
View Code

[SDOI2011]染色

线段树要lazy,好久没写竟然能一次写对。一直wa,最后才发现自己脑袋大开用运算符重载没注意加的顺序。

{$inline on}

type

  arr1=record

    toward,next:longint;

  end;

  arr2=record

    col1,col2,sum:longint;

  end;

  arr3=record

    left,right,mark:longint;

  end;

 

const

  maxn=600000;

 

var

  tree1:array[0..maxn]of arr2;

  tree2:array[0..maxn]of arr3;

  edge:array[0..maxn]of arr1;

  first,num,hash,col,fa,size,maxson,top,dep:array[0..maxn]of longint;

  chose:array[0..maxn] of boolean;

  tot,total,n,m:longint;

 

procedure addedge(j,k:longint);inline;

begin

  inc(total);

  edge[total].toward:=k;

  edge[total].next:=first[j];

  first[j]:=total;

end;

 

procedure swap(var x,y:longint);inline;

var

  i:longint;

begin

  i:=x;

  x:=y;

  y:=i;

end;

 

procedure dfs(x:longint);inline;

var

  i,too:longint;

begin

  chose[x]:=false;

  size[x]:=1;

  i:=first[x];

  while i<>0 do begin

    too:=edge[i].toward;

    if chose[too] then begin

      fa[too]:=x;

      dfs(too);

      size[x]:=size[x]+size[too];

      if size[maxson[x]]<size[too] then maxson[x]:=too;

    end;

    i:=edge[i].next;

  end;

end;

 

procedure make(x,y,depth:longint);inline;

var

  i,too:longint;

begin

  chose[x]:=false;

  inc(tot);

  num[x]:=tot;

  hash[tot]:=col[x];

  dep[x]:=depth;

  top[x]:=y;

  i:=first[x];

  if maxson[x]<>0 then make(maxson[x],y,depth);

  while i<>0 do begin

    too:=edge[i].toward;

    if (chose[too]) and (too<>maxson[x]) then

      make(too,too,depth+1);

    i:=edge[i].next;

  end;

end;

 

operator +(const lx,rx:arr2)x:arr2;inline;

begin

  if lx.sum=0 then begin

    x.col1:=rx.col1;

    x.col2:=rx.col2;

    x.sum:=rx.sum;

  end

  else

  if rx.sum=0 then begin

    x.col1:=lx.col1;

    x.col2:=lx.col2;

    x.sum:=lx.sum;

  end

  else begin

    x.col1:=lx.col1;

    x.col2:=rx.col2;

    x.sum:=lx.sum+rx.sum;

    if lx.col2=rx.col1 then dec(x.sum);

  end;

end;

 

procedure build(x,l,r:longint);inline;

var

  mid:longint;

begin

  tree2[x].left:=l;

  tree2[x].right:=r;

  tree2[x].mark:=-1;

  if l=r then begin

    tree1[x].col1:=hash[l];

    tree1[x].col2:=hash[l];

    tree1[x].sum:=1;

    exit;

  end;

  mid:=(l+r)>>1;

  build(x<<1,l,mid);

  build(x<<1+1,mid+1,r);

  tree1[x]:=tree1[x<<1]+tree1[x<<1+1];

end;

 

procedure maintain(x,y:longint);inline;

begin

  tree2[x].mark:=y;

  tree1[x].col1:=y;

  tree1[x].col2:=y;

  tree1[x].sum:=1;

end;

 

procedure pushdown(x:longint);inline;

begin

  if tree2[x].mark<>-1 then begin

    maintain(x<<1,tree2[x].mark);

    maintain(x<<1+1,tree2[x].mark);

    tree2[x].mark:=-1;

    tree1[x]:=tree1[x<<1]+tree1[x<<1+1];

  end;

end;

 

procedure change(x,ll,rr,zz:longint);inline;

var

  mid:longint;

begin

  if (tree2[x].left=ll) and (tree2[x].right=rr) then begin

    maintain(x,zz);

    exit;

  end;

  pushdown(x);

  mid:=(tree2[x].left+tree2[x].right)>>1;

  if ll>mid then change(x<<1+1,ll,rr,zz)

    else

      if rr<=mid then change(x<<1,ll,rr,zz)

        else begin

          change(x<<1,ll,mid,zz);

          change(x<<1+1,mid+1,rr,zz);

        end;

  tree1[x]:=tree1[x<<1]+tree1[x<<1+1];

end;

 

function asksum(x,ll,rr:longint):arr2;inline;

var

  mid:longint;

begin

  pushdown(x);

  if (tree2[x].left=ll) and (tree2[x].right=rr) then exit(tree1[x]);

  mid:=(tree2[x].left+tree2[x].right)>>1;

  if ll>mid then exit(asksum(x<<1+1,ll,rr))

  else

    if rr<=mid then exit(asksum(x<<1,ll,rr))

    else exit(asksum(x<<1,ll,mid)+asksum(x<<1+1,mid+1,rr));

end;

 

 

procedure querysum(x,y:longint);inline;

var

  tmp1,tmp2,tmp:arr2;

begin

  tmp1.sum:=0;

  tmp2.sum:=0;

  if dep[x]>dep[y] then swap(x,y);

  while dep[x]<dep[y] do begin

    tmp2:=asksum(1,num[top[y]],num[y])+tmp2;

    y:=fa[top[y]];

  end;

  while top[x]<>top[y] do begin

    tmp1:=asksum(1,num[top[x]],num[x])+tmp1;

    x:=fa[top[x]];

    tmp2:=asksum(1,num[top[y]],num[y])+tmp2;

    y:=fa[top[y]];

  end;

  if num[x]<=num[y] then begin

    swap(tmp1.col1,tmp1.col2);

    tmp1:=tmp1+asksum(1,num[x],num[y]);

    tmp1:=tmp1+tmp2;

  end

  else begin

    swap(tmp2.col1,tmp2.col2);

    tmp:=asksum(1,num[y],num[x]);

    tmp2:=tmp2+tmp;

    tmp1:=tmp2+tmp1;

  end;

  writeln(tmp1.sum);

end;

 

procedure color(x,y,v:longint);inline;

begin

 if dep[x]<dep[y] then swap(x,y);

 while dep[x]>dep[y] do

  begin

   change(1,num[top[x]],num[x],v);

   x:=fa[top[x]];

  end;

 while top[x]<>top[y] do

  begin

   change(1,num[top[x]],num[x],v);

   change(1,num[top[y]],num[y],v);

   x:=fa[top[x]];

   y:=fa[top[y]];

  end;

 x:=num[x];

 y:=num[y];

 if x>y then swap(x,y);

 change(1,x,y,v);

end;

 

procedure into;inline;

var

  i,j,k:longint;

begin

  read(n,m);

  fillchar(tree1,sizeof(tree1),0);

  fillchar(tree2,sizeof(tree2),0);

  for i:=1 to n do read(col[i]);

  total:=0;

  fillchar(first,sizeof(first),0);

  for i:=1 to n-1 do begin

    readln(j,k);

    addedge(j,k);

    addedge(k,j);

  end;

  fillchar(chose,sizeof(chose),true);

  dfs(1);

  fillchar(chose,sizeof(chose),true);

  make(1,1,1);

  build(1,1,n)

end;

 

procedure work;inline;

var

  j,k,l:longint;

  ch:char;

begin

  while m>0 do begin

    dec(m);

    read(ch);

    if ch='Q' then begin

      readln(j,k);

      querysum(j,k);

    end

    else begin

      readln(j,k,l);

      color(j,k,l);

    end;

  end;

end;

 

begin

  into;

  work;

end.
View Code

bz3083遥远的国度

这道题要yy一下。

查询子树很显然想到要dfs序,然后如果root=x就直接找整个树,否则算lca(root,x),如果lca(root,x)不等于x,那么此时x的子树还是原子树(画图yy),否则x原子树中包括了root,那么就反过来,找x除包括root子树外的值,这个值就是root到x的路径的最后一个点(记为j),故区间就是[1,in[j]-1]和[out[j]+1,n]。

type

  arr1=record

    toward,next:longint;

  end;

  arr2=record

    left,right,mark:longint;

    min:int64;

  end;

 

const

  maxn=800100;

  mm=18;

 

var

  edge:array[0..maxn]of arr1;

  tree:array[0..maxn]of arr2;

  first,top,num1,num2,fa,maxson,size,hash,dep,deep,pow,value:array[0..maxn]of longint;

  chose:array[0..maxn]of boolean;

  f:array[0..maxn,0..mm]of longint;

  root,n,m,tot,total:longint;

 

procedure swap(var x,y:longint);

var

  i:longint;

begin

  i:=x;

  x:=y;

  y:=i;

end;

 

function min(x,y:int64):int64;

begin

  if x<y then exit(x);

  exit(y);

end;

 

procedure addedge(j,k:longint);

begin

  inc(total);

  edge[total].toward:=k;

  edge[total].next:=first[j];

  first[j]:=total;

end;

 

procedure dfs(x:longint);

var

  i,too:longint;

begin

  chose[x]:=false;

  i:=first[x];

  size[x]:=1;

  maxson[x]:=0;

  while i<>0 do begin

    too:=edge[i].toward;

    if chose[too] then begin

      deep[too]:=deep[x]+1;

      fa[too]:=x;

      dfs(too);

      inc(size[x],size[too]);

      if size[maxson[x]]<size[too] then maxson[x]:=too;

    end;

    i:=edge[i].next;

  end;

end;

 

procedure make(x,y,depth:longint);

var

  i,too:longint;

begin

  chose[x]:=false;

  inc(tot);

  num1[x]:=tot;

  hash[tot]:=value[x];

  top[x]:=y;

  dep[x]:=depth;

  if maxson[x]<>0 then make(maxson[x],y,depth);

  i:=first[x];

  while i<>0 do begin

    too:=edge[i].toward;

    if chose[too] and (maxson[x]<>too) then make(too,too,depth+1);

    i:=edge[i].next;

  end;

  num2[x]:=tot;

end;

 

procedure update(x:longint);

begin

  tree[x].min:=min(tree[x<<1].min,tree[x<<1+1].min);

end;

 

procedure maintain(x,y:longint);

begin

  tree[x].min:=y;

  tree[x].mark:=y;

end;

 

procedure pushdown(x:longint);

begin

  if tree[x].mark<>-1 then begin

    maintain(x<<1,tree[x].mark);

    maintain(x<<1+1,tree[x].mark);

    update(x);

    tree[x].mark:=-1;

  end;

end;

 

procedure build(x,l,r:longint);

var

  mid:longint;

begin

  tree[x].left:=l;

  tree[x].right:=r;

  tree[x].mark:=-1;

  if l=r then begin

    tree[x].min:=hash[l];

    exit;

  end;

  tree[x].min:=maxlongint<<2;

  mid:=(l+r)>>1;

  build(x<<1,l,mid);

  build(x<<1+1,mid+1,r);

  update(x);

end;

 

procedure change(x,ll,rr:longint;y:int64);

var

  mid:longint;

begin

  if (tree[x].left=ll) and (tree[x].right=rr) then begin

    maintain(x,y);

    exit;

  end;

  pushdown(x);

  mid:=(tree[x].left+tree[x].right)>>1;

  if ll>mid then change(x<<1+1,ll,rr,y)

  else

    if rr<=mid then change(x<<1,ll,rr,y)

    else begin

      change(x<<1,ll,mid,y);

      change(x<<1+1,mid+1,rr,y);

    end;

  update(x);

end;

 

function askmin(x,ll,rr:longint):int64;

var

  mid:longint;

begin

  if tree[x].left<>tree[x].right then pushdown(x);

  if (tree[x].left=ll) and (tree[x].right=rr) then exit(tree[x].min);

  mid:=(tree[x].left+tree[x].right)>>1;

  if ll>mid then exit(askmin(x<<1+1,ll,rr))

  else

    if rr<=mid then exit(askmin(x<<1,ll,rr))

    else

      exit(min(askmin(x<<1,ll,mid),askmin(x<<1+1,mid+1,rr)));

end;

 

procedure color(x,y:longint;v:int64);

begin

  if dep[x]<dep[y] then swap(x,y);

  while dep[x]>dep[y] do begin

    change(1,num1[top[x]],num1[x],v);

    x:=fa[top[x]];

  end;

  while top[x]<>top[y] do begin

    change(1,num1[top[x]],num1[x],v);

    change(1,num1[top[y]],num1[y],v);

    x:=fa[top[x]];

    y:=fa[top[y]];

  end;

  x:=num1[x];

  y:=num1[y];

  if x>y then swap(x,y);

  change(1,x,y,v);

end;



procedure atfirst1;//inline;

var

  i,j:longint;

begin

  pow[0]:=1;

  for i:=1 to mm do pow[i]:=pow[i-1]<<1;

  for i:=1 to n do f[i,0]:=fa[i];

  for i:=1 to mm do

    for j:=1 to n do

      f[j,i]:=f[f[j,i-1],i-1];

end;

 

function lca(x,y:longint):longint;//inline;

var

  i:longint;

begin

  if deep[x]<deep[y] then swap(x,y);

  for i:=mm downto 0 do

    if deep[x]-pow[i]>=deep[y] then x:=f[x,i];

  if x=y then exit(x);

  for i:=mm downto 0 do

    if f[x,i]<>f[y,i] then begin

      x:=f[x,i];

      y:=f[y,i];

    end;

  exit(f[x,0]);

end;

 

procedure solve(x:longint);//inline;

var

  i,j:longint;

  ans:int64;

begin

  if x=root then begin

    writeln(askmin(1,1,n));

    exit;

  end;

  i:=lca(root,x);

  if i<>x then writeln(askmin(1,num1[x],num2[x]))

  else begin

    j:=root;

    for i:=mm downto 0 do

      if deep[f[j,i]]>deep[x] then

        j:=f[j,i];

    ans:=maxlongint<<2;

    if num1[j]>1 then ans:=min(ans,askmin(1,1,num1[j]-1));

    if num2[j]<n then ans:=min(ans,askmin(1,num2[j]+1,n));

    writeln(ans);

  end;

end;

 

procedure into;

var

  i,j,k:longint;

begin

  readln(n,m);

  total:=0;

  fillchar(first,sizeof(first),0);

  for i:=1 to n-1 do begin

    readln(j,k);

    addedge(j,k);

    addedge(k,j);

  end;

  for i:=1 to n do

    read(value[i]);

  readln(root);

  fillchar(chose,sizeof(chose),true);

  deep[1]:=1;

  dfs(1);

  fillchar(chose,sizeof(chose),true);

  make(1,1,1);

  build(1,1,n);

  atfirst1;

end;

 

procedure work;inline;

var

  i,j,k:longint;

  l:int64;

begin

  for i:=1 to m do begin

    read(j);

    case j of

      1:readln(root);

      2:begin

          readln(j,k,l);

          color(j,k,l);

      end;

      3:begin

          readln(j);

          solve(j);

      end;

    end;

  end;

end;

 

 

begin

  into;

  work;

end.
View Code
原文地址:https://www.cnblogs.com/Macaulish/p/6492114.html