zoukankan      html  css  js  c++  java
  • 线段树模板

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

    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

    愿你出走半生,归来仍是少年

  • 相关阅读:
    2017-2018-1 课表
    所编裴书练习参考解答封面 [购买了书的同志记得一定要邮件联系, 并加我微信, 方便更正错误. 这里更新有时会慢, 或者懒得弄.]
    人工智能图片放大
    猜15个名人
    Excel 当前行高亮
    2014年至今的博文目录(更新至2019年1月7日,2017篇)
    拓扑学中凝聚点的几个等价定义
    江苏省2017年高等数学竞赛本二试题(含解答)
    裴礼文数学分析中的典型问题与方法第4章一元函数积分学练习
    2017年华东师范大学数学竞赛(数学类)试题
  • 原文地址:https://www.cnblogs.com/forever97/p/segtree.html
Copyright © 2011-2022 走看看