洛谷P3372 【模板】线段树 1

P3372 【模板】线段树 1

  • 153通过
  • 525提交
  • 题目提供者HansBug
  • 标签
  • 难度普及+/提高

提交  讨论  题解

最新讨论

  • 【模板】线段树1(AAAAAAAAA…
  • 【模板】线段树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数据范围内)

分析:涉及到区间操作,那么利用lazy-tag思想,当需要处理到本区间时,不必往下处理,打上标记,当需要用的时候下传标记即可.

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

long long n, m,sum[3000000],tag[3000000];

void pushdown(int l, int r, int o)
{
    if (tag[o])
    {
        int mid = (l + r) >> 1;
        tag[o * 2] += tag[o];
        tag[o * 2 + 1] += tag[o];
        sum[o * 2] += tag[o] * (mid - l + 1);
        sum[o * 2 + 1] += tag[o] * (r - mid);
        tag[o] = 0;
    }
}

void build(int l, int r, int o)
{
    if (l == r)
    {
        scanf("%lld", &sum[o]);
        return;
    }
    int mid = (l + r) >> 1;
    build(l, mid, o * 2);
    build(mid + 1, r, o * 2 + 1);
    sum[o] = sum[o * 2] + sum[o * 2 + 1];
}

void update(int L, int R, int v, int l, int r, int o)
{
    if (L <= l && r <= R)
    {
        tag[o] += v;
        sum[o] += v * (r - l + 1);
        return;
    }
    pushdown(l, r, o);
    int mid = (l + r) >> 1;
    if (L <= mid)
        update(L, R, v, l, mid, o * 2);
    if (R > mid)
        update(L, R, v, mid + 1, r, o * 2 + 1);
    sum[o] = sum[o * 2] + sum[o * 2 + 1];
}

long long query(int L, int R, int l, int r, int o)
{
    if (L <= l && r <= R)
        return sum[o];
    if (L > r || R < l)
        return 0;
    pushdown(l, r, o);
    int mid = (l + r) >> 1;
    return query(L, R, l, mid, o * 2) + query(L, R, mid + 1, r, o * 2 + 1);
}

int main()
{
    scanf("%lld%lld", &n, &m);
    build(1, n, 1);

    for (int i = 1; i <= m; i++)
    {
        int id, x, y, k;
        scanf("%d", &id);
        if (id == 1)
        {
            scanf("%d%d%d", &x, &y, &k);
            update(x, y, k, 1, n, 1);
        }
        if (id == 2)
        {
            scanf("%d%d", &x, &y);
            printf("%lld\n", query(x,y,1,n,1));
        }
    }

    return 0;
}
时间: 2024-10-08 16:37:27

洛谷P3372 【模板】线段树 1的相关文章

洛谷—— 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(节省内存版)

题目描述 如题,已知一个数列,你需要进行下面两种操作: 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标记打在区间上,不再递归左

AC自动机(附洛谷P3769模板题)

首先,介绍一下AC自动机(Aho-Corasick automaton),是一种在一个文本串中寻找每一个已给出的模式串的高效算法. 在学习AC自动机之前,你需要先学习Trie树和KMP算法,因为AC自动机正式利用并结合了两者的思想. 说到实际的不同,其实AC自动机只是在Trie树上引入了一个类似KMP中next数组的东西叫做Fail指针. 对于每一个节点,Fail指针指向该节点所代表的字符串中,次长的.在Trie树中存在的后缀(因为最长的在Trie树种存在的后缀就是其本身)所代表的节点. 举例: