线段树(可能还会有树状数组吧)

看了下gdkoi2014……觉得完蛋了……除了一道莫队还可以写写一眼看出,其他基本不行……

发现学了一大堆东西都不会用……

那就从最基础的线段树还是吧。

都说了只是开坑还没写呢⁄(⁄ ⁄•⁄ω⁄•⁄ ⁄)⁄

POJ - 1151 Atlantis

妈蛋,都不会写线段树了……这道傻叉题竟然写了一个早上+一个下午&……

以前学的时候就一直搞乱云说的点树和区间树的区别。

都怪自己弱呵呵。

这道题竟然用lazy了……我到底是有多傻逼&(然后看了别人的代码终于醒悟)

type
  arr1=record
    left,right,tot,mark:longint;
    sum:double;
  end;
  arr2=record
    x,y1,y2:double;
    col:longint;
  end;

const
  maxn=300000;

var
  tree:array[0..maxn]of arr1;
  line:array[0..maxn]of arr2;
  hash,long:array[0..maxn]of double;
  num:array[0..maxn]of longint;
  total,n,t:longint;

procedure qsort1(l,r:longint);
var
  i,j:longint;
  mid,tmp:double;
begin
  i:=l;
  j:=r;
  mid:=hash[(l+r)>>1];
  repeat
    while hash[i]<mid do inc(i);
    while hash[j]>mid do dec(j);
    if i<=j then begin
      tmp:=hash[i];
      hash[i]:=hash[j];
      hash[j]:=tmp;
      inc(i);
      dec(j);
    end;
  until i>j;
  if i<r then qsort1(i,r);
  if l<j then qsort1(l,j);
end;

procedure qsort2(l,r:longint);
var
  i,j:longint;
  mid:double;
  tmp:arr2;
begin
  i:=l;
  j:=r;
  mid:=line[(l+r)>>1].x;
  repeat
    while line[i].x<mid do inc(i);
    while line[j].x>mid do dec(j);
    if i<=j then begin
      tmp:=line[i];
      line[i]:=line[j];
      line[j]:=tmp;
      inc(i);
      dec(j);
    end;
  until i>j;
  if i<r then qsort2(i,r);
  if l<j then qsort2(l,j);
end;

function find(x:double):longint;
var
  left,right,mid:longint;
begin
  left:=1;
  right:=total+1;
  while left+1<right do begin
    mid:=(left+right)>>1;
    if long[mid]=x then exit(mid);
    if long[mid]<x then left:=mid
      else right:=mid;
  end;
  exit(left);
end;

procedure build(x,l,r:longint);
var
  mid:longint;
begin
  tree[x].sum:=0;
  tree[x].left:=l;
  tree[x].right:=r;
  tree[x].tot:=0;
  mid:=(l+r)>>1;
  if l+1=r then exit;
  build(x<<1,l,mid);
  build(x<<1+1,mid,r);
end;

procedure update(x:longint);
begin
  if tree[x].tot>0 then
    tree[x].sum:=long[tree[x].right]-long[tree[x].left]
  else
    if tree[x].right-tree[x].left=1 then tree[x].sum:=0
      else
        tree[x].sum:=tree[x<<1].sum+tree[x<<1+1].sum;
end;

procedure change(x,ll,rr,y:longint);
var
  mid:longint;
begin
  if (tree[x].left=ll) and (tree[x].right=rr) then begin
    inc(tree[x].tot,y);
    update(x);
    exit;
  end;
  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,rr,y);
        end;
  update(x);
end;

procedure into;
var
  i:longint;
  x1,y1,x2,y2,yy:double;
begin
  for i:=1 to n do begin
    readln(x1,y1,x2,y2);
    line[i<<1-1].x:=x1;
    line[i<<1-1].y1:=y1;
    line[i<<1-1].y2:=y2;
    line[i<<1]:=line[i<<1-1];
    line[i<<1-1].col:=1;
    line[i<<1].col:=-1;
    line[i<<1].x:=x2;
    hash[i<<1-1]:=y1;
    hash[i<<1]:=y2;
  end;
  qsort1(1,n<<1);
  total:=1;
  num[1]:=1;
  long[1]:=hash[1];
  for i:=2 to n<<1 do begin
    if hash[i]<>hash[i-1] then begin
      inc(total);
      long[total]:=hash[i];
    end;
    num[i]:=total;
  end;
  qsort2(1,n<<1);
  build(1,1,total);
end;

procedure work;
var
  i,j:longint;
  ans:double;
begin
  ans:=0;
  for i:=1 to n<<1-1 do begin
    change(1,find(line[i].y1),find(line[i].y2),line[i].col);
    if line[i].x<>line[i+1].x then
      ans:=ans+(line[i+1].x-line[i].x)*tree[1].sum;
  end;
  writeln('Test case #',t);
  writeln('Total explored area: ',ans:0:2);
  writeln;
end;

begin
  t:=0;
  while true do begin
    readln(n);
    if n=0 then break;
    inc(t);
    into;
    work;
  end
end.
View Code

最后还被格式小小得坑了……&

点树和区间树区别在于[l,r]的两个儿子区间,如果是点树是[l,mid][mid+1,r]边界条件是l=r而区间树则是[l,mid][mid,r]边界条件是l+1=r。

bzoj 3306: 树

出题人什么心态,没写数据范围,害我以为是我的程序错了……

这题是bzoj3083的弱化版……我竟然还写了那么久

后来拿3083的程序(当时的题解http://hi.baidu.com/macaulish64/item/33fd9adbbb21b80738f6f746)交&……发现速度差不多……我的树链这么快么?

不说了竟然弱到这个地步

type
  arr1=record
    left,right:longint;
    min:int64;
  end;
  arr2=record
    toward,next:longint;
  end;
 
const
  maxn=400600;
 
var
  tree:array[0..maxn]of arr1;
  edge:array[0..maxn]of arr2;
  numin,numout,first,deep:array[0..maxn]of longint;
  hash,value:array[0..maxn]of int64;
  fa:array[0..maxn,0..20]of longint;
  n,root,esum,m,mm,time:longint;
 
function min(x,y:int64):int64;
begin
  if x<y then exit(x);
  exit(y);
end;
 
procedure addedge(i,j:longint);
begin
  inc(esum);
  edge[esum].toward:=j;
  edge[esum].next:=first[i];
  first[i]:=esum;
end;
 
procedure swap(var x,y:longint);
var
  i:longint;
begin
  i:=x;
  x:=y;
  y:=i;
end;
 
procedure dfs(x:longint);
var
  i,too:longint;
begin
  inc(time);
  numin[x]:=time;
  hash[time]:=value[x];
  i:=first[x];
  while i>0 do begin
    too:=edge[i].toward;
    deep[too]:=deep[x]+1;
    dfs(too);
    i:=edge[i].next;
  end;
  numout[x]:=time;
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].min:=hash[l];
    exit;
  end;
  tree[x].min:=maxlongint<<3;
  mid:=(l+r)>>1;
  build(x<<1,l,mid);
  build(x<<1+1,mid+1,r);
  tree[x].min:=min(tree[x<<1].min,tree[x<<1+1].min);
end;
 
procedure change(x,y:longint;z:int64);
var
  mid:longint;
begin
  if (tree[x].left=y) and (tree[x].right=y) then begin
    tree[x].min:=z;
    exit;
  end;
  mid:=(tree[x].left+tree[x].right)>>1;
  if y<=mid then change(x<<1,y,z)
    else change(x<<1+1,y,z);
  tree[x].min:=min(tree[x<<1].min,tree[x<<1+1].min);
end;
 
function askmin(x,l,r:longint):int64;
var
  mid:longint;
begin
  if (tree[x].left=l) and (tree[x].right=r) then exit(tree[x].min);
  mid:=(tree[x].left+tree[x].right)>>1;
  if l>mid then exit(askmin(x<<1+1,l,r))
  else
    if r<=mid then exit(askmin(x<<1,l,r))
    else
      exit(min(askmin(x<<1,l,mid),askmin(x<<1+1,mid+1,r)));
end;
 
function lca(x,y:longint):longint;
var
  i:longint;
begin
  if deep[x]<deep[y] then swap(x,y);
  for i:=mm downto 0 do
    if deep[y]+1<=deep[fa[x,i]] then
      x:=fa[x,i];
  if y=fa[x,0] then exit(x)
    else x:=fa[x,0];
  for i:=mm downto 1 do
    if fa[x,i]<>fa[y,i] then begin
      x:=fa[x,i];
      y:=fa[y,i];
    end;
  exit(x);
end;
 
procedure into;
var
  i,j:longint;
begin
  readln(n,m);
  for i:=1 to n do begin
    readln(fa[i,0],value[i]);
    if fa[i,0]=0 then root:=i
      else addedge(fa[i,0],i);
  end;
  deep[root]:=1;
  dfs(root);
  build(1,1,n);
  mm:=trunc(ln(n)/ln(2))+1;
  for j:=1 to mm do
    for i:=1 to n do
      fa[i,j]:=fa[fa[i,j-1],j-1];
end;
 
procedure work;
var
  ch:char;
  x,i:longint;
  l:int64;
begin
  while m>0 do begin
    dec(m);
    read(ch);
    if ch='Q' then begin
      readln(x);
      if x=root then writeln(tree[1].min)
      else begin
        i:=lca(root,x);
        if fa[i,0]<>x then writeln(askmin(1,numin[x],numout[x]))
        else
          if numout[i]<n then
            writeln(min(askmin(1,1,numin[i]-1),askmin(1,numout[i]+1,n)))
          else writeln(askmin(1,1,numin[i]-1));
      end;
    end
    else
    if ch='V' then begin
      readln(i,l);
      change(1,numin[i],l);
    end
    else readln(root);
  end;
end;
 
begin
  into;
  work
end.
View Code

UVA 11297 Census

 二维线段树裸题,单点修改,区间查询

半小时敲完不用调直接1a我也是蛮拼的

算是第一次敲二维线段树(虽然不难);

二维线段树要注意的就是大树到小树,而小树节点也要根据大树的叶节点进行调整

好累(但是rausen大神一天切好多题啊)

type
  arr1=record
    left,right:longint;
  end;
  arr2=record
    left,right,min,max:longint;
  end;

const
  maxn=4000;

var
  tree1:array[0..maxn]of arr1;
  tree2:array[0..maxn,0..maxn]of arr2;
  a:array[0..505,0..505]of longint;
  x1,x2,y1,y2,n,m,ansmin,ansmax: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 buildsmall(x0,x,l,r:longint);
var
  mid:longint;
begin
  tree2[x0][x].left:=l;
  tree2[x0][x].right:=r;
  if l=r then begin
    if tree1[x0].left=tree1[x0].right then begin
      tree2[x0][x].min:=a[tree1[x0].left][l];
      tree2[x0][x].max:=tree2[x0][x].min;
    end
    else begin
      tree2[x0][x].min:=min(tree2[x0<<1][x].min,tree2[x0<<1+1][x].min);
      tree2[x0][x].max:=max(tree2[x0<<1][x].max,tree2[x0<<1+1][x].max);
    end;
    exit;
  end;
  mid:=(l+r)>>1;
  buildsmall(x0,x<<1,l,mid);
  buildsmall(x0,x<<1+1,mid+1,r);
  tree2[x0][x].min:=min(tree2[x0][x<<1].min,tree2[x0][x<<1+1].min);
  tree2[x0][x].max:=max(tree2[x0][x<<1].max,tree2[x0][x<<1+1].max);
end;

procedure buildbig(x,l,r:longint);
var
  mid:longint;
begin
  tree1[x].left:=l;
  tree1[x].right:=r;
  if l=r then
    buildsmall(x,1,1,m)
  else begin
    mid:=(l+r)>>1;
    buildbig(x<<1,l,mid);
    buildbig(x<<1+1,mid+1,r);
    buildsmall(x,1,1,m);
  end;
end;

procedure querysmall(x0,x,l,r:longint);
var
  mid:longint;
begin
  if (tree2[x0][x].left=l) and (tree2[x0][x].right=r) then begin
    ansmin:=min(ansmin,tree2[x0][x].min);
    ansmax:=max(ansmax,tree2[x0][x].max);
    exit;
  end;
  mid:=(tree2[x0][x].left+tree2[x0][x].right)>>1;
  if l>mid then querysmall(x0,x<<1+1,l,r)
    else
      if r<=mid then querysmall(x0,x<<1,l,r)
      else begin
        querysmall(x0,x<<1,l,mid);
        querysmall(x0,x<<1+1,mid+1,r);
      end;
end;

procedure querybig(x,l,r:longint);
var
  mid:longint;
begin
  if (tree1[x].left=l) and (tree1[x].right=r) then begin
    querysmall(x,1,y1,y2);
    exit;
  end;
  mid:=(tree1[x].left+tree1[x].right)>>1;
  if l>mid then querybig(x<<1+1,l,r)
    else
      if r<=mid then querybig(x<<1,l,r)
      else begin
        querybig(x<<1,l,mid);
        querybig(x<<1+1,mid+1,r);
      end;
end;

procedure changesmall(x0,x:longint);
var
  mid:longint;
begin
  if tree2[x0][x].left=tree2[x0][x].right then begin
    if tree1[x0].left=tree1[x0].right then begin
      tree2[x0][x].min:=a[tree1[x0].left][tree2[x0][x].left];
      tree2[x0][x].max:=tree2[x0][x].min;
    end
    else begin
      tree2[x0][x].min:=min(tree2[x0<<1][x].min,tree2[x0<<1+1][x].min);
      tree2[x0][x].max:=max(tree2[x0<<1][x].max,tree2[x0<<1+1][x].max);
    end;
    exit;
  end;
  mid:=(tree2[x0][x].left+tree2[x0][x].right)>>1;
  if y1<=mid then changesmall(x0,x<<1)
    else changesmall(x0,x<<1+1);
  tree2[x0][x].min:=min(tree2[x0][x<<1].min,tree2[x0][x<<1+1].min);
  tree2[x0][x].max:=max(tree2[x0][x<<1].max,tree2[x0][x<<1+1].max);
end;

procedure changebig(x:longint);
var
  mid:longint;
begin
  if tree1[x].left=tree1[x].right then begin
    changesmall(x,1);
    exit;
  end;
  mid:=(tree1[x].left+tree1[x].right)>>1;
  if x1<=mid then changebig(x<<1)
    else changebig(x<<1+1);
  changesmall(x,1);
end;

procedure into;
var
  i,j:longint;
begin
  readln(n,m);
  for i:=1 to n do
    for j:=1 to m do
      read(a[i,j]);
  readln;
  buildbig(1,1,n);
end;

procedure work;
var
  q:longint;
  ch:char;
begin
  readln(q);
  while q>0 do begin
    dec(q);
    read(ch);
    if ch='q' then begin
      readln(x1,y1,x2,y2);
      ansmax:=-maxlongint;
      ansmin:=maxlongint;
      querybig(1,x1,x2);
      writeln(ansmax,' ',ansmin);
    end
    else begin
      readln(x1,y1,a[x1,y1]);
      changebig(1);
    end;
  end;
end;

begin
  into;
  work;
  readln;
  readln
end.
View Code

(为什么我的sb线段树要记录left和right&……算了都习惯了就不改了)

脑洞大想写二维线段树区间修改加区间查询(结果不会问了iwtwiioi大神还是不会,是不是没救了)

云说是写不出的……

原文地址:https://www.cnblogs.com/Macaulish/p/4296746.html