• 线段树


    线段树,类似区间树,是一个完全二叉树,它在各个节点保存一条线段(数组中的一段子数组),主要用于高效解决连续区间的动态查询问题,由于二叉结构的特性,它基本能保持每个操作的复杂度为O(lgN)!

    性质:父亲的区间是[a,b],(c=(a+b)/2)左儿子的区间是[a,c],右儿子的区间是[c+1,b],线段树需要的空间为数组大小的四倍

    证明线段树需要的空间为数组大小的四倍:

    设根区间为[1,n],根据二叉树的性质:

      1,二叉树的总节点数N=N0+N1+N2

      2,N=二叉树的总度数+1=0×N0+1×N1+2×N2

    又有线段树的N1=0,N0=n,N2=N0+1=n+1

    可得线段树的总节点数N=2×n+1

    若采用数组来存放,则根据二叉树的性质:

      3,节点数为N的完全二叉树,树的高度为(log2n)+1

      4,高度为h的二叉树最多有2h-1个节点

    又线段树是一颗完全二叉树

    可得数组的最大长度应为2^((log2n)+1)-1=4n-1

    1.单点更新,区间求和,例题:HDU 1166

     1 #include<stdio.h>
     2 #include<string.h>
     3 #define lson l,mid,rt<<1
     4 #define rson mid+1,r,rt<<1|1
     5 const int N=50000+11;
     6 int a[N<<2];
     7 void getdown(int rt)
     8 {
     9     a[rt]=a[rt<<1]+a[rt<<1|1];
    10 }
    11 void build(int l,int r,int rt)
    12 {
    13     if(l==r)
    14     {
    15         scanf("%d",&a[rt]);
    16         return ;
    17     }
    18     int mid=(l+r)>>1;
    19     build(lson);
    20     build(rson);
    21     getdown(rt);
    22 }
    23 void updata(int p,int x,int l,int r,int rt)
    24 {
    25     if(l==r)
    26     {
    27         a[rt]+=x;
    28         return ;
    29     }
    30     int mid=(l+r)>>1;
    31     if(p<=mid)    updata(p,x,lson);
    32     else        updata(p,x,rson);
    33     getdown(rt);
    34 }
    35 int Q(int L,int R,int l,int r,int rt)
    36 {
    37     if(L<=l&&R>=r)    return a[rt];
    38     int ans=0;
    39     int mid=(l+r)>>1;
    40     if(L<=mid)    ans+=Q(L,R,lson);
    41     if(R>mid)    ans+=Q(L,R,rson);
    42     return ans;
    43 }
    44 int main()
    45 {
    46     int t,cas=0,n;
    47     scanf("%d",&t);
    48     while(t--)
    49     {
    50         scanf("%d",&n);
    51         build(1,n,1);
    52         char s[10];int x,y;
    53         printf("Case %d:
    ",++cas);
    54         while(scanf("%s",s)&&s[0]!='E')
    55         {
    56             scanf("%d%d",&x,&y);
    57             if(s[0]=='Q')    printf("%d
    ",Q(x,y,1,n,1));
    58             if(s[0]=='A')    updata(x,y,1,n,1);
    59             if(s[0]=='S')    updata(x,-y,1,n,1);
    60         }
    61     }
    62     return 0;
    63 }
    View Code

     2.区间更新,区间求和,例题:POJ 3468

     1 #include<stdio.h>
     2 #include<string.h>
     3 #define lson l,mid,rt<<1
     4 #define rson mid+1,r,rt<<1|1
     5 typedef long long ll;
     6 const int N=1e5+11;
     7 ll add[N<<2],sum[N<<2];
     8 void Pushup(int rt)
     9 {
    10     sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    11 }
    12 void Pushdown(int rt,int d)
    13 {
    14     if(add[rt])
    15     {
    16         add[rt<<1]+=add[rt];
    17         add[rt<<1|1]+=add[rt];
    18         sum[rt<<1]+=add[rt]*(d-(d>>1));
    19         sum[rt<<1|1]+=add[rt]*(d>>1);
    20         add[rt]=0;
    21     }
    22 }
    23 void build(int l,int r,int rt)
    24 {
    25     add[rt]=0;
    26     if(l==r)
    27     {
    28         scanf("%I64d",&sum[rt]);
    29         return ;
    30     }
    31     int mid=(l+r)>>1;
    32     build(lson);build(rson);
    33     Pushup(rt);
    34 }
    35 void updata(int L,int R,int x,int l,int r,int rt)
    36 {
    37     if(L<=l&&R>=r)
    38     {
    39         add[rt]+=x;
    40         sum[rt]+=(ll)x*(r-l+1);
    41         return ;
    42     }
    43     Pushdown(rt,r-l+1);
    44     int mid=(l+r)>>1;
    45     if(L<=mid)    updata(L,R,x,lson);
    46     if(R>mid)    updata(L,R,x,rson);
    47     Pushup(rt);
    48 }
    49 ll Q(int L,int R,int l,int r,int rt)
    50 {
    51     if(L<=l&&R>=r)
    52         return sum[rt];
    53     Pushdown(rt,r-l+1);
    54     int mid=(l+r)>>1;
    55     ll ans=0;
    56     if(L<=mid)    ans+=Q(L,R,lson);
    57     if(R>mid)    ans+=Q(L,R,rson);
    58     return ans;
    59 }
    60 int main()
    61 {
    62     int n,m,x,y,z;
    63     char op[2];
    64     scanf("%d%d",&n,&m);
    65      build(1,n,1);
    66      while(m--)
    67      {
    68          scanf("%s",op);
    69          if(op[0]=='C')
    70          {
    71              scanf("%d%d%d",&x,&y,&z);
    72              updata(x,y,z,1,n,1);
    73          }
    74          else
    75          {
    76              scanf("%d%d",&x,&y);
    77              printf("%I64d
    ",Q(x,y,1,n,1));
    78          }
    79      }
    80     return 0;
    81 }
    View Code

     参考文章:http://blog.csdn.net/metalseed/article/details/8039326

  • 相关阅读:
    【CodeForces 611C】New Year and Domino
    【HDU 1003】 Max Sum
    【ZOJ 3502】Contest
    【LightOJ 1422】Halloween Costumes(区间DP)
    【ZOJ 3609】Modular Inverse
    乘法逆元及其应用
    除法和取余的运算时间
    HUD3689 Infinite monkey theorem
    POJ2185 Milking Grid
    1355: [Baltic2009]Radio Transmission[循环节]
  • 原文地址:https://www.cnblogs.com/L-King/p/5372079.html
Copyright © 2020-2023  润新知