洛谷 P3372 【模板】线段树 1

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置。

题目链接:https://www.luogu.org/problem/show?pid=3372

题目描述

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

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标记的线段树模板。

AC代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 #include<cmath>
 5
 6 using namespace std;
 7 const int MAXN = 100000 + 10;
 8 inline void read(int &x)
 9 {//快速读入
10     char ch = getchar();char c;x = 0;
11     while(ch > ‘9‘ || ch < ‘0‘)    c = ch,ch = getchar();
12     while(ch <= ‘9‘ && ch >= ‘0‘) x = x*10+ch-‘0‘,ch = getchar();
13 }
14 int n,m,num[MAXN];
15 long long stdata[MAXN << 2],stlazy[MAXN << 2];
16 void build(int o,int l,int r)
17 {//建立线段树
18     if(l == r)
19     {
20         stdata[o] = num[l];
21         return;
22     }
23     int mid = (l + r) >> 1;
24     build(o << 1,l,mid);
25     build(o << 1 | 1,mid + 1,r);
26     stdata[o] = stdata[o << 1] + stdata[o << 1|1];
27 }
28
29 void putdown(int o,int l,int r)
30 {
31     stlazy[o << 1] += stlazy[o];
32     stlazy[o << 1|1] += stlazy[o];
33     int mid = (l + r) >> 1;
34     stdata[o << 1] += (mid - l + 1)*stlazy[o];
35     stdata[o << 1|1] += (r - mid)*stlazy[o];
36     stlazy[o] = 0;
37 }
38
39 void s_modify(int ll,int rr,int k,int o,int l,int r)
40 {//区间修改
41     if(ll <= l && rr >= r)
42     {
43         stdata[o] += (r - l + 1)*k;
44         stlazy[o] += k;
45         return;
46     }
47     int mid = (l + r) >> 1;
48     if(stlazy[o]) putdown(o,l,r);
49     if(mid >= ll)    s_modify(ll,rr,k,o << 1,l,mid);
50     if(mid < rr)    s_modify(ll,rr,k,o << 1|1,mid + 1,r);
51     stdata[o] = stdata[o << 1] + stdata[o << 1|1];
52 }
53
54 long long ask(int ll,int rr,int o,int l,int r)
55 {//区间询问
56     if(ll <= l && rr >= r)
57         return stdata[o];
58     if(stlazy[o])    putdown(o,l,r);
59     int mid = (l + r) >> 1;
60     long long ans = 0;
61     if(mid >= ll) ans += ask(ll,rr,o << 1,l,mid);
62     if(mid < rr)  ans += ask(ll,rr,o << 1|1,mid + 1,r);
63     return ans;
64 }
65
66 int main()
67 {
68     read(n),read(m);
69     for(int i = 1;i <= n;i ++)
70         read(num[i]);
71     build(1,1,n);
72     int op,x,y,k;
73     for(int i = 1;i <= m;i ++)
74     {
75         read(op);
76         if(op == 1)
77         {
78             read(x),read(y),read(k);
79             s_modify(x,y,k,1,1,n);
80         }
81         else
82         {
83             read(x),read(y);
84             long long t = ask(x,y,1,1,n);
85             printf("%lld\n",t);
86         }
87     }
88     return 0;
89 }
时间: 2024-11-08 19:47:06

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

洛谷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

题目描述 如题,已知一个数列,你需要进行下面两种操作: 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树种存在的后缀就是其本身)所代表的节点. 举例: