标签:洛谷 int 线段 tr long add 区间 const 模板
原题链接:
题目:
如题,已知一个数列,你需要进行下面两种操作:
1、将某区间每一个数加上 k。
2、求出某区间每一个数的和。
输入格式:
第一行包含两个整数 n,m,分别表示该数列数字的个数和操作的总个数。
第二行包含 n 个用空格分隔的整数,其中第 i 个数字表示数列第 i 项的初始值。
接下来 m 行每行包含 3 或 4 个整数,表示一个操作,具体如下:
1 x y k 表示将[x, y]区间内的数都加上k
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
说明:
所有数据范围:1 ≤ n, m ≤ 1e5
答案在long long 范围内。
思路:
这题为什么要用线段树来写呢,那就是因为区间修改,区间查询了吧,如果是区间修改,单点查询,
用树状数组他不香吗,那么线段树的区间修改又涉及到了懒标记的运用。
线段树的区间操作可以使用懒标记来优化时间复杂度,具体实现就得写一个pushdown函数,作用是将
懒标记的值传给他的儿子,这样就可以将查询前的n步操作化为一步,大大优化了时间复杂度,具体实现并
不复杂,重要的还是多练(我还是太菜了)。
#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
typedef pair<int, int> PII;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const int N = 1e5 + 10;
int n, m;
int w[N];
struct Node{
int l, r;
int sum, add;
}tr[N << 2];
void pushup(int u){
tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
}
void pushdown(int u){ //pushdown操作里的sum += x我开始写成了 =,所有改了好久,痛心疾首
if(tr[u].add){
tr[u << 1].sum += (tr[u << 1].r - tr[u << 1].l + 1) * tr[u].add;
tr[u << 1 | 1].sum += (tr[u << 1 | 1].r - tr[u << 1 | 1].l + 1) * tr[u].add;
tr[u << 1].add += tr[u].add;
tr[u << 1 | 1].add += tr[u].add;
tr[u].add = 0;
}
}
void build(int u, int l, int r){
tr[u].l = l, tr[u].r = r;
if(l == r) tr[u].sum = w[l];
else{
int mid = l + r >> 1;
build(u << 1, l, mid); build(u << 1 | 1, mid + 1, r);
pushup(u);
}
}
void modify(int u, int l, int r, int k){ //包含在指定区间内再操作,包含的运算符想清楚再写,就不会debug这么久
if(tr[u].l >= l && tr[u].r <= r){
tr[u].sum += (tr[u].r - tr[u].l + 1) * k;
tr[u].add += k;
}
else{
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
if(l <= mid) modify(u << 1, l, r, k);
if(r > mid) modify(u << 1 | 1, l, r, k);
pushup(u);
}
}
int query(int u, int l, int r){
if(tr[u].l >= l && tr[u].r <= r){
//cout << tr[u].l << " " << tr[u].r << endl;
return tr[u].sum;
}
else{
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
int res = 0;
if(l <= mid) res += query(u << 1, l, r);
if(r > mid) res += query(u << 1 | 1, l, r);
return res;
}
}
signed main(void){
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n >> m;
for(int i = 1; i <= n; i++)
cin >> w[i];
build(1, 1, n);
for(int i = 1; i <= m; i++){
int op, l, r, k;
cin >> op >> l >> r;
if(op == 1){
cin >> k;
modify(1, l, r, k);
}
else{
cout << query(1, l, r) << endl;
}
}
return 0;
}
标签:洛谷,int,线段,tr,long,add,区间,const,模板 来源: https://www.cnblogs.com/ReSakura/p/16216304.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。