zoukankan      html  css  js  c++  java
  • 洛谷 P3372 【模板】线段树 加法

    题目描述

    如题,已知一个数列,你需要进行下面两种操作:

    1.将某区间每一个数加上x

    2.求出某区间每一个数的和

    输入输出格式

    输入格式:

     

    第一行包含两个整数N、M,分别表示该数列数字的个数和操作的总个数。

    第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。

    接下来M行每行包含3或4个整数,表示一个操作,具体如下:

    操作1: 格式:1 x y k 含义:将区间[x,y]内每个数加上k

    操作2: 格式:2 x y 含义:输出区间[x,y]内每个数的和

     

    输出格式:

     

    输出包含若干行整数,即为所有操作2的结果。

    输入输出样例

    输入样例#1: 
    5 5
    1 5 4 2 3
    2 2 4
    1 2 3 2
    2 3 4
    1 1 5 1
    2 1 4
    输出样例#1: 
    11
    8
    20

    说明

    时空限制:1000ms,128M

    数据规模:

    对于30%的数据:N<=8,M<=10

    对于70%的数据:N<=1000,M<=10000

    对于100%的数据:N<=100000,M<=100000

    (数据已经过加强^_^,保证在int64/long long数据范围内)

    AC代码:

     1 #include<iostream>
     2 using namespace std;
     3 long long n,m,a[10000005],p,x,y,pp;
     4 struct kkk{
     5     int l,r;//l、r分别代表此节点所含信息区间左端和右端 
     6     long long add,tql;//add是lazy标记,tql代表此节点所含区间和。 
     7 }t[10000005];
     8 void build(int q,int w,int e) {
     9     t[q].l = w;t[q].r = e;
    10     if(w == e) { //如果只维护一个节点的信息,说明为叶节点 
    11         t[q].tql = a[w];
    12         return ;    
    13     } 
    14     int mid = w + e >> 1;
    15     build(2*q, w, mid);     //建左子树 
    16     build(2*q+1, mid+1, e); //建右子树 
    17     t[q].tql = t[q*2].tql + t[q*2+1].tql; //一个节点的信息由它的左右儿子得来 
    18 }
    19 void spr(int o) {//运用lazy标记进行区间修改 
    20     if(t[o].add) {
    21         t[2*o].tql += t[o].add * (t[2*o].r - t[2*o].l + 1);
    22         t[o*2+1].tql += t[o].add * (t[o*2+1].r - t[o*2+1].l + 1);
    23         t[o*2].add += t[o].add;
    24         t[o*2+1].add += t[o].add;
    25         t[o].add = 0;
    26     }
    27 }
    28 void pl(int o,int l,int r,int k) {
    29     if(l <= t[o].l && r >= t[o].r) {//如果已知区间被所求全部包含,那么直接计算即可 
    30         t[o].tql += (long long) k * (t[o].r - t[o].l + 1);
    31         t[o].add += k;
    32         return ;
    33     }
    34     spr(o);
    35     int mid = t[o].l + t[o].r >> 1;
    36     if(x <= mid) pl(o*2,x,y,k);//如果x<=mid,说明左半区间包含要求区间 
    37     if(y > mid) pl(o*2+1,x,y,k); //如果x>=mid ,说明右半区间包含要求区间 
    38     t[o].tql = t[o*2].tql + t[o*2+1].tql;
    39 }
    40 long long pr(int p,int x,int y){
    41     if(x <= t[p].l && y >= t[p].r) return t[p].tql;
    42     spr(p);
    43     int mid = t[p].l + t[p].r >> 1;
    44     long long ans = 0;
    45     if(x<=mid) ans += pr(p*2,x,y);//如果x<=mid,说明左半子树包含答案 
    46     if(y>mid) ans += pr(p*2+1,x,y);//如果x>mid,说明右半子树包含答案 
    47     return ans;
    48 }
    49 int main(){
    50     cin >> n >> m;
    51     for(int i = 1;i <= n; i++) cin >> a[i];
    52     build(1,1,n);//建树 
    53     for(int i = 1;i <= m; i++) {
    54         cin >> p;
    55         if(p == 1) {
    56             cin >> x >> y >> pp;
    57             pl(1,x, y, pp);
    58         }
    59         else {
    60             cin >> x >> y;
    61             cout << pr(1,x,y) << endl;
    62         }
    63     }
    64     
    65     return 0;
    66 } 
  • 相关阅读:
    AndRodi Strudio中的按钮时件
    Intent(三)向下一个活动传递数据
    Intent(二)隐式调用intent
    用PopupWindow做下拉框
    环形进度条
    Android Studio分类整理res/Layout中的布局文件(创建子目录)
    Android无需申请权限拨打电话
    使用ViewPager切换Fragment时,防止频繁调用OnCreatView
    定制 黑色描边、白色背景、带圆角 的背景
    Android 底部弹出Dialog(横向满屏)
  • 原文地址:https://www.cnblogs.com/lipeiyi520/p/10539549.html
Copyright © 2011-2022 走看看