洛谷P3372 【模板】线段树 1(节省内存版)

题目描述

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

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数据范围内)

看了mhy12345写的【真(jia)·主流】线段树,我都怀疑是他自己写的,不过确实省一半内存,不多说,代码来了233

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 100000
#define MAXT MAXN*4
long long a[MAXN+2];
struct sgt_node
{
    int lc,rc;
    long long sum,lazy;
}sgt[MAXT];
int n,m,topt = 0;
#define smid ((l+r)>>1)
#define lch sgt[now].lc
#define rch sgt[now].rc

void update(int now){
    sgt[now].sum = sgt[lch].sum + sgt[rch].sum;
}

void set_lazy(int now,int l,int r,long long v){
    sgt[now].sum += (r-l+1) * v;
    sgt[now].lazy += v;
}

void push_down(int now,int l,int r){
    if(sgt[now].lazy){
        set_lazy(lch,l,smid,sgt[now].lazy);
        set_lazy(rch,smid+1,r,sgt[now].lazy);
        sgt[now].lazy = 0;
    }
}

void Build_sgt(int &now,int l,int r){
    now = ++topt;
    if(l == r){
        sgt[now].sum = a[l];
        return ;
    }
    Build_sgt(lch,l,smid);
    Build_sgt(rch,smid+1,r);
    update(now);
}

long long Query_sgt(int now,int l,int r,int x,int y){
    if(x==l && y==r) return sgt[now].sum;
    push_down(now,l,r);
    if(y<=smid) return Query_sgt(lch,l,smid,x,y);
    if(x>smid) return Query_sgt(rch,smid+1,r,x,y);
    return Query_sgt(lch,l,smid,x,smid) + Query_sgt(rch,smid+1,r,smid+1,y);
}

void Add_sgt(int now,int l,int r,int x,int y,long long v){
    if(l==x && r==y){
        set_lazy(now,l,r,v);
        return ;
    }
    push_down(now,l,r);
    if(y<=smid) Add_sgt(lch,l,smid,x,y,v);
    else if(x>smid) Add_sgt(rch,smid+1,r,x,y,v);
    else{
        Add_sgt(lch,l,smid,x,smid,v);
        Add_sgt(rch,smid+1,r,smid+1,y,v);
    }
    update(now);
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
      scanf("%d",&a[i]);
    int root = 0;
    Build_sgt(root,1,n);
    int s,x,y,k;
    for(int i=1;i<=m;i++){
        scanf("%d",&s);
        if(s==1){
            scanf("%d%d%d",&x,&y,&k);
            Add_sgt(1,1,n,x,y,k);
        }
        else if(s==2){
            scanf("%d%d",&x,&y);
            printf("%lld\n",Query_sgt(1,1,n,x,y));
        }
    }
    return 0;
}

出处:mhy12345

时间: 2024-10-22 12:49:31

洛谷P3372 【模板】线段树 1(节省内存版)的相关文章

算法模板——线段树4(区间加+区间乘+区间覆盖值+区间求和)

实现功能——1:区间加法 2:区间乘法 3:区间覆盖值 4:区间求和 这是个四种常见线段树功能的集合版哦...么么哒(其实只要协调好三种tag的关系并不算太难——前提是想明白了线段树的工作模式) 代码长度几经修改后也大为缩水 还有!!!——通过BZOJ1798反复的尝试,我的出来一个重要结论——尽量减少pushup操作的不必要使用次数,对于程序提速有明显的效果!!! 1 type vet=record 2 a0,a1:longint; 3 end; 4 var 5 i,j,k,l,m,n,a1,

洛谷P3372 【模板】线段树 1

P3372 [模板]线段树 1 153通过 525提交 题目提供者HansBug 标签 难度普及+/提高 提交  讨论  题解 最新讨论 [模板]线段树1(AAAAAAAAA- [模板]线段树1 洛谷评测机出问题了吗? 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. 第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值. 接

洛谷—— P3372 【模板】线段树 1

P3372 [模板]线段树 1 题目描述 如题,已知一个数列,你需要进行下面两种操作: 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]内每个数的

洛谷P3372线段树模板1——线段树

题目:https://www.luogu.org/problemnew/show/P3372 线段树模板. 代码如下: #include<iostream> #include<cstdio> using namespace std; long long n,m,a[100005],ct; struct N{ long long lazy,sum; long long ls,rs; }p[200005]; void pushdown(long long cur,long long l

洛谷 P3372 【模板】线段树 1

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置. 题目链接:https://www.luogu.org/problem/show?pid=3372 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个数. 第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值. 接下来M行每行包含3或4个整数,表示一个操作,具体如下

【洛谷P3372】【模板】线段树 1

题目描述 如题,已知一个数列,你需要进行下面两种操作: 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]内每个数的和 输出格式: 输出包含若干行整

【树状数组区间加+区间查询模板】洛谷P3372

虽然说这道题线段树很好做,但毕竟树状数组常数小又好写,所以还是写个模板吧. 区间加转为前缀加 区间和转为前缀和 我们讨论一个1~k的区间加x对于一个前缀和val[i]的影响 对于所有k<i的更新,对val[i]的贡献为val[i]+=k*x 对于所有k>=i的更新,对val[i]的贡献为val[i]+=i*x 所以我们维护记录两个数组,对于每次更新 a[k]+=x;b[k]+=k*x; 所以对于一个值的前缀和val[i]=b[1~i]+(a[i+1]~a[now])*i; 然后询问的时候前缀减

线段树_区间加乘(洛谷P3373模板)

题目描述 如题,已知一个数列,你需要进行下面三种操作: 1.将某区间每一个数乘上x 2.将某区间每一个数加上x 3.求出某区间每一个数的和 输入格式: 第一行包含三个整数N.M.P,分别表示该数列数字的个数.操作的总个数和模数. 第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值. 接下来M行每行包含3或4个整数,表示一个操作,具体如下: 操作1: 格式:1 x y k 含义:将区间[x,y]内每个数乘上k 操作2: 格式:2 x y k 含义:将区间[x,y]内每个数加上k

【线段树】【P3372】模板-线段树

百度百科 Definition&Solution 线段树是一种log级别的树形结构,可以处理区间修改以及区间查询问题.期望情况下,复杂度为O(nlogn). 核心思想见百度百科,线段树即将每个线段分成左右两个线段做左右子树.一个线段没有子树,当且仅当线段表示的区间为[a,a]. 由于编号为k的节点的子节点为2k以及2k+1,线段树可以快速的递归左右叶节点. lazy标记:当进行区间修改的时候,如果一个区间整体全部被包含于要修改的区间,则可以将该区间的值修改后,将lazy标记打在区间上,不再递归左