zoukankan      html  css  js  c++  java
  • poj 3468 A Simple Problem with Integers 线段树第一次 + 讲解

     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

    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

    报告
    题目大意: 一串数,“C a b c" 表示在区间[a,b]中每个数 + c
    "Q a b"表示查询区间[a,b] 的和

    线段树: 学习了线段树后的第一道题。这道题包含了线段树的Pushdown,Pushup,Query,Build,Update几个函数,很好地让初学者了解了线段树的用法和精髓--延迟更新,即每次更新时只是做一个标记,当要查找时才继续向下更新。还要注意的是,有些题不需要向下回溯(pushup),也不需要延迟更新(pushdown),甚至连更新都不用。但是需要根据题意改变要查找的内容和更新的内容,有的需要找最大值,有的需要找和,等等,需要随机应变。线段树能解决的问题,树状数组不一定能解决,但是树状数组能解决的,线段树一定能解决。

    思路: 便不多说。上代码。
      1 #include<iostream>
      2 #include<cstring>
      3 #include<string>
      4 #include<cstdio>
      5 #define L(u) (u<<1)
      6 #define R(u) (u<<1|1)//没有分号 
      7 using namespace std;
      8 int n,q;
      9 long long c;
     10 long long a[100005];
     11 struct node{
     12     int l,r;
     13     long long add,sum;
     14 };
     15 char s[2];
     16 node pp[400005];/**数据范围**/
     17 void pushup(int u)
     18 {
     19     pp[u].sum=pp[L(u)].sum+pp[R(u)].sum;
     20     return ;
     21 }
     22 void pushdown(int u)
     23 {
     24     pp[L(u)].add+=pp[u].add;
     25     pp[L(u)].sum+=(pp[L(u)].r-pp[L(u)].l+1)*pp[u].add;
     26     pp[R(u)].add+=pp[u].add;
     27     pp[R(u)].sum+=(pp[R(u)].r-pp[R(u)].l+1)*pp[u].add;
     28     pp[u].add=0;/*!!!*/
     29 }
     30 void update(int u,int left,int right,long long t)
     31 {
     32     if (left<=pp[u].l&&pp[u].r<=right)
     33     {
     34         pp[u].add+=t;
     35         pp[u].sum+=(pp[u].r-pp[u].l+1)*t;
     36         return ;
     37     }
     38     pp[u].sum+=(right-left+1)*t;
     39     if (pp[u].add) pushdown(u);
     40     int mid=(pp[u].l+pp[u].r)>>1;
     41     if (right<=mid) update(L(u),left,right,t);
     42     else /***/if (left>mid) update(R(u),left,right,t);
     43     else
     44     {
     45         update(L(u),left,mid,t);
     46         update(R(u),mid+1,right,t);
     47     }
     48     //pushup(u);
     49 }
     50 
     51 void build(int u,int left,int right)
     52 {
     53     pp[u].l=left;
     54     pp[u].r=right;
     55     pp[u].add=0;
     56     if (pp[u].l==pp[u].r)
     57     {
     58         pp[u].sum=a[left];//*****
     59         return ;
     60     }
     61     int mid=(pp[u].l+pp[u].r)>>1;
     62     build(L(u),left,mid);
     63     build(R(u),mid+1,right);
     64     pushup(u);
     65 }
     66 long long query(int u,int left,int right)
     67 {
     68     if (left==pp[u].l&&pp[u].r==right)
     69         return pp[u].sum;
     70     if (pp[u].add) pushdown(u);
     71     int mid=(pp[u].l+pp[u].r)>>1;
     72     if (right<=mid) return query(L(u),left,right);
     73     if (left>mid) return query(R(u),left,right);
     74     else
     75       return (query(L(u),left,mid)+query(R(u),mid+1,right));
     76 }
     77 int main()
     78 {
     79     //freopen("tree.in","r",stdin);
     80     cin>>n>>q;
     81     for (int i=1;i<=n;i++)
     82           scanf("%lld",&a[i]);//long long 读数 
     83     build(1,1,n);
     84     for (int i=1;i<=q;i++)
     85     {
     86         scanf("%s",s);
     87         if (s[0]=='Q')
     88         {    
     89             int k,b;
     90             scanf("%d%d",&k,&b);
     91             cout<<query(1,k,b)<<endl;
     92         }
     93         else
     94         {
     95             int k,b;
     96             cin>>k>>b>>c;
     97             update(1,k,b,c);
     98         }
     99     }
    100     
    101     return 0;
    102 }
    注意事项:1、数据范围:线段树一般定义4*n
    2、#difine 的使用 function() ( ** ) 注意括号没有分号;
         3、runtime error :运行错误 long long a[i], %lld(linux) %I64d (windows)
         4、模板答题

    顺便抱怨一下,poj的评测系统太慢了,waiting了好久.......












  • 相关阅读:
    【刷题】面筋-mysql-如何对数据库进行备份
    【刷题】面筋-数据库-mysql的优化
    【刷题】面筋-MySQL中char、varchar和text三者的区别
    【刷题】面筋-sql-学生成绩单里两门成绩>80的学生名字
    【刷题】面筋-网络-无效链接,死链接,错误链接
    【刷题】面筋-算法-在海量IP中找出访问次数最多的100个IP
    【刷题】面筋-shell:统计一个文件中重复的行和重复次数
    【刷题】面筋-linux-如何查找出现频率最高的100个ip地址
    【刷题】面筋-linux 如何将文件从一台服务器转移到另一台服务器
    【刷题】面筋-Linux-vi显示或关闭行号:set number
  • 原文地址:https://www.cnblogs.com/lx0319/p/5667947.html
Copyright © 2011-2022 走看看