zoukankan      html  css  js  c++  java
  • 数据结构(线段树+树状数组)合集

    线段树:

    1、【codevs1690】开关灯

    这道题是一道线段树裸题,可以开个标记记录当前节点被修改的次数,然后仿照区间修改区间查询来做就行了。

    代码:

    uses math;
    type hh=record
      l,r,x,sum:longint;
    end;
    var a:array[0..400010]of hh;
      n,m,i,x,l,r:longint;
    function calc(now:longint):longint;
    begin
      exit(a[now].r-a[now].l+1);
    end;
    procedure build(now,l,r:longint);
    begin
      a[now].l:=l; a[now].r:=r; a[now].x:=0; a[now].sum:=0;
      if l<>r then begin
        build(now<<1,l,(l+r)>>1); build(now<<1 or 1,(l+r)>>1+1,r);
      end;
    end;
    procedure change(now,l,r:longint);
    begin
      if(l<=a[now].l)and(a[now].r<=r)then begin
        a[now].x:=a[now].x xor 1; a[now].sum:=calc(now)-a[now].sum;
      end
      else begin
        if l<a[now<<1 or 1].l then change(now<<1,l,r);
        if a[now<<1].r<r then change(now<<1 or 1,l,r);
        a[now].sum:=a[now<<1].sum+a[now<<1 or 1].sum;
        if a[now].x=1 then a[now].sum:=calc(now)-a[now].sum;
      end;
    end;
    function query(now,l,r:longint):longint;
    var ret:longint;
    begin                                                                     
      if(l=a[now].l)and(a[now].r=r)then exit(a[now].sum)
      else begin
        ret:=0;
        if l<a[now<<1 or 1].l then ret:=ret+query(now<<1,l,min(r,a[now<<1].r));
        if a[now<<1].r<r then ret:=ret+query(now<<1 or 1,max(l,a[now<<1 or 1].l),r);
        if a[now].x=0 then exit(ret)
        else exit(r-l+1-ret);
      end;
    end;
    begin
      read(n,m);
      build(1,1,n);
      for i:=1 to m do begin
        read(x,l,r);
        if x=0 then change(1,l,r)
        else writeln(query(1,l,r));
      end;
    end.
    View Code

    (虽然是一道裸题,但我还是WA了好几天)

    2、【codevs1299】切水果

    这道题是典型的区间set+区间查询,不过因为是全区间查询,所以可以直接输出根节点的sum(Hqy神犇这道写了一个25行线段树,%%%)

    代码:

    type tree=record
      l,r,sum:longint;
      en:boolean;
    end;
    var a:array[0..2000100]of tree;
      n,m,i,l,r:longint;
    procedure build(now,l,r:longint);
    begin
      a[now].l:=l; a[now].r:=r; a[now].sum:=r-l+1; a[now].en:=false;
      if l<>r then begin
        build(now<<1,l,(l+r)>>1); build(now<<1 or 1,(l+r)>>1+1,r);
      end;
    end;
    procedure cut(now,l,r:longint);
    begin 
      if a[now].en then exit;
      if(l<=a[now].l)and(a[now].r<=r)then begin
        a[now].en:=true; a[now].sum:=0; exit;
      end;
      if l<a[now<<1 or 1].l then cut(now<<1,l,r);
      if a[now<<1].r<r then cut(now<<1 or 1,l,r);
      a[now].sum:=a[now<<1].sum+a[now<<1 or 1].sum;
      if(a[now<<1].en)and(a[now<<1 or 1].en)then a[now].en:=true;
    end;
    begin
      read(n,m);
      build(1,1,n);
      for i:=1 to m do begin
        read(l,r);
        cut(1,l,r);
        writeln(a[1].sum);
      end;
    end.
    View Code

    ==========================分割线================================

    树状数组:

    1、【codevs1228】苹果树

    这道题乍一看以为是树剖,蓝鹅我不会……

    于是看了看题解,看到了一种神奇的思路:

    因为是单点修改+子树查询,所以我们就能利用树的dfs的序的性质:一颗子树的所有节点一定会在dfs序中挤在一坨。

    所以我们就能求出dfs序,记录每个节点在dfs序中的位置和以它为根的子树所代表的区间,然后就能愉快地单点修改+区间查询了。

    代码:

    var a,ne:array[0..200010]of longint;
      h,x,y,q,c,cou:array[0..100010]of longint;
      b:array[0..100010]of boolean;
      n,m,i,k,u,v,num:longint;
      ch:char;
    procedure add(x,y:longint);
    begin
      inc(m); a[m]:=y; ne[m]:=h[x]; h[x]:=m;
    end;
    procedure dfs(now:longint);
    var i:longint;
    begin
      inc(m); q[now]:=m; x[now]:=m; b[now]:=false;
      i:=h[now];
      while i>0 do begin
        if b[a[i]] then dfs(a[i]);
        i:=ne[i];
      end;
      y[now]:=m;
    end;
    function lowbit(x:longint):longint;
    begin
      exit(x and -x);
    end;
    procedure change(x,num:longint);
    begin
      while x<=n do begin
        c[x]:=c[x]+num;
        x:=x+lowbit(x);
      end;
    end;
    function sum(x:longint):longint;
    begin
      sum:=0;
      while x>0 do begin
        sum:=sum+c[x];
        x:=x-lowbit(x);
      end;
    end;
    begin
      read(n); m:=0;
      fillchar(h,sizeof(h),255);
      for i:=1 to n-1 do begin
        read(u,v);
        add(u,v); add(v,u);
      end;
      fillchar(b,sizeof(b),true);
      m:=0;
      dfs(1);
      fillchar(c,sizeof(c),0);
      for i:=1 to n do begin
        cou[i]:=1; change(i,1);
      end;
      readln(m);
      for i:=1 to m do begin
        readln(ch,k);
        if ch='Q' then writeln(sum(y[k])-sum(x[k]-1))
        else begin
          cou[q[k]]:=-cou[q[k]];
          change(q[k],cou[q[k]]);
        end;
      end;
    end.
    View Code

     =======================算了不更了===============================

  • 相关阅读:
    判断一张view 是否被加载过用 nil == view.superview
    oracle9i新增sql命令merge
    Windows平台个人常用软件推荐
    ASPxSpinEdit高度无法控件的解决办法
    Oracle编码约定
    宾克斯的酒 
    “dcom项目无属性”的解决方法
    安装VS2005后找不到工具箱的解决办法
    奇怪问题一个
    Oracle临时表空间不够,导致查询出错。
  • 原文地址:https://www.cnblogs.com/quzhizhou/p/6534580.html
Copyright © 2011-2022 走看看