线段树模板

     线段树其实复习的不是什么思想,主要应该是自己的代码风格与边界处理,就直接由题目来复习吧。另外,重新理解一下线段树的操作原理对于做题时很有帮助的。比赛前一定要耐心看一下每一种线段树的建树与维护方式。

pascal模板

不修改的RMQ:

例题:vijosP1514 天才的记忆

var
  x,y,i,j,k,l,m,n:longint;
  tree,a:array[0..1200000] of longint;
function max(a,b:longint):longint;
begin
  if a>b then exit(a);
  exit(b);
end;
{建树}
procedure build_tree(l,r,num:longint);
var
  mid:longint;
begin
  if l=r then begin
    tree[num]:=a[l];
    exit;
  end;
  mid:=(l+r)>>1;
  build_tree(l,mid,num<<1);
  build_tree(mid+1,r,num<<1+1);
  tree[num]:=max(tree[num<<1],tree[num<<1+1]);
end;
{求解区间极值}
function query(l,r,num:longint):longint;
var
  mid:longint;
begin
  if (x<=l)and(y>=r) then exit(tree[num]);
  mid:=(l+r)>>1;
  if x>mid then exit(query(mid+1,r,num<<1+1)) else
  if y<=mid then exit(query(l,mid,num<<1)) else
 exit(max(query(l,mid,num<<1),query(mid+1,r,num<<1+1)));
end;
begin
  readln(n);
  for i:=1 to n do
  read(a[i]);
  readln;
  build_tree(1,n,1);
  readln(m);
  for i:=1 to m do
  begin
    readln(x,y);
    writeln(query(1,n,1));
  end;
end.
View Code

单点更新区间求和:

例题:hduP1166 敌兵布阵

var
  a:array[1..100100] of longint;
  tree:array[1..100100] of longint;
  i,j,n,m,t,x,y,u:longint;
  ch:char;
{建树}
procedure build_tree(l,r,num:longint);
var
  mid:longint;
begin
  if l=r then begin
    tree[num]:=a[l];
    exit;
  end
  else begin
    mid:=(l+r) shr 1;
    build_tree(l,mid,num shl 1);
    build_tree(mid+1,r,num shl 1+1);
    tree[num]:=tree[num shl 1]+tree[num shl 1+1];
  end;
end;
{单点修改}
procedure add(l,r,num:longint);
var
  mid:longint;
begin
  if (l=r) then
  begin
    inc(tree[num],y);
    exit;
  end;
  mid:=(l+r)shr 1;
  if x<=mid then
  begin
    add(l,mid,num shl 1);
    inc(tree[num],y);
  end
  else begin
    add(mid+1,r,num shl 1+1);
    inc(tree[num],y);
  end;
end;
{区间求和}
function sum(l,r,num:longint):longint;
var
  mid:longint;
begin
  if l=r then exit(tree[num]);
  mid:=(l+r)shr 1;
  if y<=mid then exit(sum(l,mid,num shl 1)) else
  if x>mid then exit(sum(mid+1,r,num shl 1+1)) else
  exit(sum(l,mid,num<<1)+sum(mid+1,r,num shl 1+1));
end;
begin
  readln(t);
  for j:=1 to t do
  begin
    writeln('Case',j,':');
    readln(n);
      for i:=1 to n do read(a[i]);
      readln;
      build_tree(1,n,1);
      read(ch);
      while ch<>'E' do
      begin
            if ch='Q' then
            begin
                  for i:=2 to 5 do read(ch);
                  read(x,y);
                  writeln(sum(1,n,1));
            end else
            if ch='A' then
            begin
                  for i:=2 to 3 do read(ch);
                  read(x,y);
                  add(1,n,1);
            end else
            begin
                  for i:=2 to 3 do read(ch);
                  read(x,y); y:=-y;
                  add(1,n,1);
            end;
            readln;
            read(ch);
      end;
      readln;
  end;
end.
View Code

单点更新区间求极值:

例题:hduP1754 I hate it 

var
  a,tree:array[1..1000000] of longint;
  n,m,l,r,x,y,t,u,i,j:longint;
  ch,ch1,ch2:char;
function max(a,b:longint):longint;
begin
  if a > b then max:=a else
  max:=b;
end;
{建树}
procedure build_tree(l,r,num:longint);
var
  mid:longint;
begin
  if l=r then begin
    tree[num]:=a[l];
    exit;
  end
  else begin
    mid:=(l+r) shr  1;
    build_tree(l,mid,num shl 1);
    build_tree(mid+1,r,num shl 1+1);
    if tree[num shl 1] > tree[num shl 1+1] then
    tree[num]:=tree[num shl 1]
    else tree[num]:=tree[num shl 1+1];
  end;
end;
{单点修改}
procedure change(l,r,num:longint);
var
  mid:longint;
begin
  if (l=r) then begin
    tree[num]:=y;
    exit;
  end;
  mid:=(l+r) shr  1;
  if x <= mid then
  begin
    change(l,mid,num shl 1);
    if tree[num shl 1] > tree[num shl 1+1] then
    tree[num]:=tree[num shl 1]
    else tree[num]:=tree[num shl 1+1];
  end
  else begin
    change(mid+1,r,num shl 1+1);
    if tree[num shl 1] > tree[num shl 1+1] then
    tree[num]:=tree[num shl 1]
    else tree[num]:=tree[num shl 1+1];
  end;
end;
{区间求极值}
function query(l,r,num:longint):longint;
var
  mid:longint;
begin
  if (x <= l)and(y >= r) then query := tree[num]
  else begin
    mid:=(l+r) shr  1;
    if y <= mid then query:=query(l,mid,num shl 1)
    else if x > mid then query:=query(mid+1,r,num shl 1+1)
    else query:=max(query(l,mid,num shl 1),query(mid+1,r,num shl 1+1));
  end;
end;
begin
  while not eof do
  begin
    readln(n,m);
    for i:=1 to n do
    read(a[i]);
    readln;
    build_tree(1,n,1);
    for i:=1 to m do
    begin
      readln(ch,x,y);
      if ch='Q' then writeln(query(1,n,1));
      if ch='U' then change(1,n,1);
    end;
  end;
end.
View Code

成端更新区间求极值

例题:vijosP1659 河蟹王国

var
  q,x,y,c,i,j,k,l,m,n:longint;
  mark,tree:array[1..600000] of longint;
  a:array[1..100000] of longint;
function max(a,b:longint):longint;
begin
  if a>b then exit(a);
  exit(b);
end;
{清除父节点的标记,将其加到父节点上,同时传递标记至子节点}
procedure clean(num:longint);
begin
  if mark[num]=0 then exit;
  inc(mark[num<<1],mark[num]);
  inc(mark[num<<1+1],mark[num]);
  inc(tree[num],mark[num]);
  mark[num]:=0;
end;
{建树}
procedure build_tree(l,r,num:longint);
var
  mid:longint;
begin
  if l=r then begin
    tree[num]:=a[l];
    exit;
  end
  else begin
    mid:=(l+r)>>1;
    build_tree(l,mid,num<<1);
    build_tree(mid+1,r,num<<1+1);
    tree[num]:=max(tree[num<<1],tree[num<<1+1]);
  end;
end;
{区间修改}
procedure add(l,r,num:longint);
var
  mid:longint;
begin
  clean(num);
  if (x<=l) and (y>=r) then
  begin
    inc(mark[num],c);
    exit;
  end;
  mid:=(l+r)>>1;
  if x>mid then
    add(mid+1,r,num<<1+1)
  else if y<=mid then
    add(l,mid,num<<1)
  else
  begin
    add(l,mid,num<<1);
    add(mid+1,r,num<<1+1);
  end;
  clean(num<<1);
  clean(num<<1+1);
  tree[num]:=max(tree[num<<1],tree[num<<1+1]);
end;
{区间求极值}
function query(l,r,num:longint):longint;
var
  mid:longint;
begin
  clean(num);
  if (x<=l)and(y>=r) then exit(tree[num]);
  mid:=(l+r)>>1;
  if y<=mid then exit(query(l,mid,num<<1))
  else if x>mid then exit(query(mid+1,r,num<<1+1))
  else exit(max(query(l,mid,num<<1),query(mid+1,r,num<<1+1)));
end;
begin
  readln(n);
  for i:=1 to n do
  readln(a[i]);
  build_tree(1,n,1);
  readln(m);
  for i:=1 to m do
  begin
    read(q);
    if q=1 then begin
      readln(x,y,c);
      add(1,n,1);
    end
    else begin
      readln(x,y);
      writeln(query(1,n,1));
    end;
  end;
end.
View Code

线段树+DP

例题:vijosP1083小白逛公园

var
  before,q,x,y,i,j,k,l,m,n:longint;
  mc,ma,mb,sum:array[1..3000000] of longint;
  tree:array[1..500001] of longint;
function max(a,b:longint):longint;
begin
  if a>b then exit(a);
  exit(b);
end;
{建树}
procedure build_tree(l,r,num:longint);
var
  mid:longint;
begin
  if l=r then begin
    ma[num]:=tree[l];
    mb[num]:=tree[l];
    sum[num]:=tree[l];
    mc[num]:=tree[l];
    exit;
  end;
  mid:=(l+r)>>1;
  build_tree(l,mid,num<<1);
  build_tree(mid+1,r,num<<1+1);
  sum[num]:=sum[num<<1]+sum[num<<1+1];
  ma[num]:=max(ma[num<<1],sum[num<<1]+ma[num<<1+1]);
  mb[num]:=max(mb[num<<1]+sum[num<<1+1],mb[num<<1+1]);
  mc[num]:=max(mc[num<<1],mc[num<<1+1]);
  mc[num]:=max(mc[num],mb[num<<1]+ma[num<<1+1]);
end;
{修改}
procedure change(l,r,num:longint);
var
  mid:longint;
begin
  if l=r then begin
    ma[num]:=y;
    mb[num]:=y;
    sum[num]:=y;
    mc[num]:=y;
    exit;
  end;
  mid:=(l+r)>>1;
  if x<=mid  then
    change(l,mid,num<<1)
  else
    change(mid+1,r,num<<1+1);
  sum[num]:=sum[num<<1]+sum[num<<1+1];
  ma[num]:=max(ma[num<<1],sum[num<<1]+ma[num<<1+1]);
  mb[num]:=max(mb[num<<1]+sum[num<<1+1],mb[num<<1+1]);
  mc[num]:=max(mc[num<<1],mc[num<<1+1]);
  mc[num]:=max(mc[num],mb[num<<1]+ma[num<<1+1]);
end;
function query:longint;
var
  mid:longint;
procedure ask(l,r,num:longint);
var
  mid:longint;
begin
  if (x<=l)and(r<=y) then
  begin
    query:=max(query,ma[num]+before);
    query:=max(query,mc[num]);
    before:=max(mb[num],sum[num]+before);
       exit;
  end;
  mid:=(l+r)>>1;
  if y<=mid then ask(l,mid,num<<1) else
  if x>mid then ask(mid+1,r,num<<1+1) else
  begin
    ask(l,mid,num<<1);
    ask(mid+1,r,num<<1+1);
  end;
end;
begin
  before:=-100000;
  query:=-100000;
  ask(1,n,1);
end;
begin
  readln(n,m);
  for i:=1 to n do
  read(tree[i]);
  build_tree(1,n,1);
  readln;
  for i:=1 to m do
  begin
    readln(q,x,y);
    if q=1 then
    begin
      if x>y then
      begin
        q:=x;
        x:=y;
        y:=q;
      end;
      writeln(query);
    end
    else change(1,n,1);
  end;
end.
View Code

 

posted @ 2013-11-17 11:52  forever97  阅读(272)  评论(0编辑  收藏  举报