• 线段树基础模块


    线段树(1)

    线段树如图,图要记清楚,就是一棵饱和二叉树,最后一排没有画的的也存在,只是没有值,所以左节点为2u,右节点为2u+1,所以对于区间【1,n】,结构体数组应为4n.

    对于线段树基础,有几个主要的模块。

    1,建立线段树(初始Build())

     1 void build(int u,int left,int right)
     2 {
     3     node[u].l=left;
     4     node[u].r=right;
     5     node[u].add=0;
     6     if(node[u].l==node[u].r)
     7     {
     8         node[u].sum=a[left];
     9         return ;//叶子节点 
    10     }
    11     int mid=(left+right)>>1;
    12     build(u*2,left,mid);
    13     build(u*2+1,mid+1,right);
    14     Pushup(u);//只赋值了叶子节点,向上更新 
    15 }

    2,更新操作(加一个值,乘一个字Updata())

     1 void updata(int u,int left,int right,int ad)
     2 {
     3     if(node[u].l==left&&node[u].r==right)
     4     {
     5         node[u].add+=ad;//有些还没有pushdouwn的.add要加上去一起更新 
     6         node[u].sum+=(right-left+1)*ad;
     7         return; 
     8     }
     9     node[u].sum+=(right-left+1)*ad;//u节点区间包含[left,right],也要加上
    10     if(node[u].add)pushdown(u);//延时向下更新 
    11     int mid=(node[u].l+node[u].r)>>1;
    12     if(right<=mid)updata(u*2,left,right,ad);
    13     else if(left>mid)updata(u*2+1,left,right,ad);//若左右边都有,分成两段计算 
    14     else 
    15     {
    16         updata(u*2,left,mid,ad);
    17         updata(u*2+1,mid+1,right,ad);//同时占有左右子树,把他分成两部分计算 
    18     }
    19     // pushup(u);因为有node[u].sum+=(right-left+1)*ad;
    20 }

    3,查询(一段区间的和Query())

     1 long long Query(int u,int left,int right)
     2 {
     3     if(node[u].l==left&&node[u].r==right)
     4     return node[u].sum;
     5     if(node[u].add)pushdown(u);//add不为0,说明还未更新,查询就要顺便向下更新(便于延时更新)
     6     int mid=(node[u].l+node[u].r)>>1;
     7     if(right<=mid)return Query(u*2,left,right);
     8     else if(left>mid)return Query(u*2+1,left,right);
     9     else 
    10         return (Query(u*2,left,mid)+Query(u*2+1,mid+1,right));
    11         
    12     //pushup(u);//同理 
    13 } 

    4,向上回溯(Pushup())

    1 void Pushup(int u)
    2 {
    3     node[u].sum=node[u*2].sum+node[u*2+1].sum;
    4     return ;
    5 } 

    5,向下延时更新(Pushdown())----为什么是延时,看下面

    1 void pushdown(int u)
    2 {
    3     node[u*2].add+=node[u].add;
    4     node[u*2].sum+=(node[u*2].r-node[u*2].l+1)*node[u].add;
    5     node[u*2+1].add+=node[u].add;
    6     node[u*2+1].sum+=(node[u*2+1].r-node[u*2+1].l+1)*node[u].add;
    7     node[u].add=0;//加完就清0,说明已经更新过了 
    8 }

    poj 3468 A Simple Problem with Integers(线段树)

    Description

    You have N integers, A1A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.

    Input

    The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.
    The second line contains N numbers, the initial values of A1A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
    Each of the next Q lines represents an operation.
    "C a b c" means adding c to each of AaAa+1, ... , Ab. -10000 ≤ c ≤ 10000.
    "Q a b" means querying the sum of AaAa+1, ... , Ab.

    Output

    You need to answer all Q commands in order. One answer in a line.

    Sample Input

    10 5
    1 2 3 4 5 6 7 8 9 10
    Q 4 4
    Q 1 10
    Q 2 4
    C 3 6 3
    Q 2 4

    Sample Output

    4
    55
    9
    15

    代码
      1 #include<iostream>
      2 #include<cstdio>
      3 #define N 100005
      4 using namespace std;
      5 int n,m;
      6 int a[N];
      7 struct Node
      8 {
      9     int l,r;//节点所包含的左右区间端点 
     10     long long sum;
     11     long long add;//add是指每个所增加的(即为C) 
     12 }node[4*N];
     13 void Pushup(int u)
     14 {
     15     node[u].sum=node[u*2].sum+node[u*2+1].sum;
     16     return ;
     17 } 
     18 void pushdown(int u)
     19 {
     20     node[u*2].add+=node[u].add;
     21     node[u*2].sum+=(node[u*2].r-node[u*2].l+1)*node[u].add;
     22     node[u*2+1].add+=node[u].add;
     23     node[u*2+1].sum+=(node[u*2+1].r-node[u*2+1].l+1)*node[u].add;
     24     node[u].add=0;//加完就清0,说明已经更新过了 
     25 }
     26 void build(int u,int left,int right)
     27 {
     28     node[u].l=left;
     29     node[u].r=right;
     30     node[u].add=0;
     31     if(node[u].l==node[u].r)
     32     {
     33         node[u].sum=a[left];
     34         return ;//叶子节点 
     35     }
     36     int mid=(left+right)>>1;
     37     build(u*2,left,mid);
     38     build(u*2+1,mid+1,right);
     39     Pushup(u);//只赋值了叶子节点,向上更新 
     40 }
     41 void updata(int u,int left,int right,int ad)
     42 {
     43     if(node[u].l==left&&node[u].r==right)
     44     {
     45         node[u].add+=ad;//有些还没有pushdouwn的.add要加上去一起更新 
     46         node[u].sum+=(right-left+1)*ad;
     47         return; 
     48     }
     49     node[u].sum+=(right-left+1)*ad;//u节点区间包含[left,right],也要加上
     50     if(node[u].add)pushdown(u);//延时向下更新 
     51     int mid=(node[u].l+node[u].r)>>1;
     52     if(right<=mid)updata(u*2,left,right,ad);
     53     else if(left>mid)updata(u*2+1,left,right,ad);//若左右边都有,分成两段计算 
     54     else 
     55     {
     56         updata(u*2,left,mid,ad);
     57         updata(u*2+1,mid+1,right,ad);//同时占有左右子树,把他分成两部分计算 
     58     }
     59     // pushup(u);因为有node[u].sum+=(right-left+1)*ad;
     60 }
     61 long long Query(int u,int left,int right)
     62 {
     63     if(node[u].l==left&&node[u].r==right)
     64     return node[u].sum;
     65     if(node[u].add)pushdown(u);//add不为0,说明还未更新,查询就要顺便向下更新
     66     int mid=(node[u].l+node[u].r)>>1;
     67     if(right<=mid)return Query(u*2,left,right);
     68     else if(left>mid)return Query(u*2+1,left,right);
     69     else 
     70         return (Query(u*2,left,mid)+Query(u*2+1,mid+1,right));
     71         
     72     //pushup(u);//同理 
     73 } 
     74 int main()
     75 {
     76     freopen("POJ3468.in","r",stdin);
     77     freopen("POJ3468.out","w",stdout);
     78     while((scanf("%d%d",&n,&m))==2)
     79     {
     80         for(int i=1;i<=n;i++)
     81     scanf("%d",&a[i]);
     82     getchar();
     83     build(1,1,n);
     84     for(int i=1;i<=m;i++)
     85     {
     86         int x,y,z;
     87         char c;
     88         scanf("%c ",&c);
     89         if(c=='Q')
     90         {
     91             scanf("%d%d",&x,&y);
     92             long long w=Query(1,x,y);
     93             cout<<w<<endl;
     94             getchar();
     95         }
     96         if(c=='C')
     97         {
     98             scanf("%d%d%d",&x,&y,&z);
     99             updata(1,x,y,z);
    100             getchar();
    101         }
    102         
    103     } 
    104     }
    105     
    106     return 0;
    107 }
  • 相关阅读:
    HTTP状态代码
    安装mySQL数据库常见问题
    python3.6安装版本选择
    用连接池提高Servlet访问数据库的效率
    策略模式
    如何在vue项目中修改less变量,多主题项目解决方案
    【前端】vue项目 url中传递数组参数
    element date-picker默认值问题
    echart 折线图legend不显示的问题
    vue学习之父子组件通信两种方法
  • 原文地址:https://www.cnblogs.com/abcfrey/p/Frey5730.html
Copyright © 2020-2023  润新知