洛谷模板题
题目描述
如题,已知一个数列,你需要进行下面两种操作:
- 将某区间每一个数加上 k k k。
- 求出某区间每一个数的和。
输入格式
-
第一行包含两个整数 n , m n, m n,m 分别表示该数列数字的个数和操作的总个数
-
第二行包含 n n n 个用空格分隔的整数,其中第 i i i 个数字表示数列第 i i i项的初始值。
-
接下来 m m m 行每行包含 3 或 4 个整数,表示一个操作,具体如下:
1
x
y
k
1\, x\, y\, k
1xyk:将区间
[
x
,
y
]
[x, y]
[x,y] 内每个数加上
k
k
k。
2
x
y
2 \,x \,y\,
2xy:输出区间
[
x
,
y
]
[x, y]
[x,y] 内每个数的和。
输出格式
输出包含若干行整数,即为所有操作 2 的结果。
70% AC代码 终于能凭一己之力写出线段树代码了
#include<iostream>
#include<cstdio>
using namespace std;
const int maxN = 100000;
int arr[maxN];
long long tree[4*maxN];
//建立线段树
void build(int node, int l, int r) {
//递归的出口
if (l == r) tree[node] = arr[l];
else {
int mid = (l + r) / 2;
int lchild = (node << 1) + 1;
int rchild = (node << 1) + 2;
build(lchild, l, mid);
build(rchild, mid + 1, r);
//计算父节点的值
tree[node] = tree[lchild] + tree[rchild];
}
}
//将区间【ql,qr】内的数加上k
void update(int node, int l, int r, int ql, int qr, int k) {
int mid = (l + r) / 2;
int lchild = (node << 1) + 1;
int rchild = (node << 1) + 2;
//递归出口
if (qr<l || ql>r) return;
if (l == r) tree[node] += k;
//当前区间与目标区间有重叠
else {
update(lchild, l, mid, ql, qr, k);
update(rchild, mid + 1, r, ql, qr, k);
tree[node] = tree[lchild] + tree[rchild];
}
}
//查询【ql,qr】区间之和
long long query(int node, int l, int r, int ql, int qr) {
int mid = (l + r) / 2;
int lchild = (node << 1) + 1;
int rchild = (node << 1) + 2;
if (l > qr || ql > r) return 0;
//如果目标区间包含当前区间返回 当前节点的值
else if (ql<=l && r <= qr) return tree[node];
else {
long long lsum = query(lchild, l, mid, ql, qr);
long long rsum = query(rchild, mid + 1, r, ql, qr);
return lsum + rsum;
}
}
int main() {
int n = 0,m=0;
scanf("%d%d", &n, &m);
//原数组赋初值
for (int i = 0; i < n; i++) scanf("%d", &arr[i]);
build(0, 0, n-1);
for (int i = 0; i < m; i++) {
int opr = 0, l = 0, r = 0, k = 0;
scanf("%d", &opr);
if (opr == 1) {
scanf("%d%d%d", &l, &r, &k);
update(0, 0, n - 1, l-1, r-1, k);
}
else {
scanf("%d%d", &l, &r);
cout << query(0, 0, n - 1, l-1, r-1)<<endl;
}
}
return 0;
}
上面的代码只能过70%的数据,即使开再大的数组也只能过70%
下面的代码优化了,加入了lazytag 通过了全部样例🤣
#include<iostream>
#include<cstdio>
using namespace std;
const int maxN = 100000;
int arr[maxN];
long long tree[4*maxN],mark[4*maxN];
void build(int node, int l, int r) {
int mid = (l + r) / 2;
int lchild = (node << 1) + 1;
int rchild = (node << 1) + 2;
if (l == r) tree[node] = arr[l];
else {
build(lchild, l, mid);
build(rchild, mid + 1, r);
tree[node] = tree[lchild] + tree[rchild];
}
}
void push_down(int node, int l, int r) {
int mid = (l + r) / 2;
int lchild = (node << 1) + 1;
int rchild = (node << 1) + 2;
mark[lchild] += mark[node];
mark[rchild] += mark[node];
tree[lchild] += (mid - l + 1)*mark[node];
tree[rchild] += (r - mid)*mark[node];
mark[node]=0;
}
//将【ql,qr】区间内的每个数加上k
void update(int node, int l, int r, int ql, int qr, int k) {
int mid = (l + r) / 2;
int lchild = (node << 1) + 1;
int rchild = (node << 1) + 2;
if (qr<l || ql>r) return;
else if (ql <= l && r <= qr) {
tree[node] += (r-l+1)*k;
if (l < r)
mark[node] += k;
}
else {
//如果有lazytag就传递下去
if(mark[node]) push_down(node, l, r);
update(lchild, l, mid, ql, qr, k);
update(rchild, mid + 1, r, ql, qr, k);
tree[node] = tree[lchild] + tree[rchild];
}
}
long long query(int node, int l, int r, int ql, int qr) {
int mid = (l + r) / 2;
int lchild = (node << 1) + 1;
int rchild = (node << 1) + 2;
if (ql > r || qr < l) return 0;
else if (ql <= l && r <= qr) {
return tree[node];
}
else {
if(mark[node]) push_down(node, l, r);
return query(lchild, l, mid, ql, qr) + query(rchild, mid + 1, r, ql, qr);
}
}
int main() {
int n=0, m=0;
scanf("%d%d",&n,&m);
for (int i = 0; i < n; i++) scanf("%d",&arr[i]);
build(0, 0, n - 1);
for (int i = 0; i < m; i++) {
int opr = 0, x = 0, y = 0, k = 0;
scanf("%d",&opr);
if (opr == 1) {
scanf("%d%d%d",&x,&y,&k);
update(0, 0, n - 1, x-1, y-1, k);
}
else {
scanf("%d%d",&x,&y);
cout << query(0, 0, n - 1, x - 1, y - 1)<<endl;
}
}
}