线段树1
该比赛已结束,您无法在比赛模式下递交该题目。您可以点击“在题库中打开”以普通模式查看和递交本题。
题目描述
如题,已知一个数列,你需要进行下面两种操作:
- 将某区间每一个数加上 。
- 求出某区间每一个数的和。
输入格式
第一行包含两个整数 ,分别表示该数列数字的个数和操作的总个数。
第二行包含 个用空格分隔的整数,其中第 个数字表示数列第 项的初始值。
接下来 行每行包含 或 个整数,表示一个操作,具体如下:
1 x y k:将区间 内每个数加上 。2 x y:输出区间 内每个数的和。
输出格式
输出包含若干行整数,即为所有操作 2 的结果。
5 5
1 5 4 2 3
2 2 4
1 2 3 2
2 3 4
1 1 5 1
2 1 4
11
8
20
提示
对于 的数据:,。 对于 的数据:,。 对于 的数据:。
保证任意时刻数列中任意元素的和在 内。
【样例解释】

暴力解法
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct node{
int l, r;
ll val;
}a[400005];
int n, m;
void pushup(int rt){
a[rt].val = a[rt << 1].val + a[rt << 1 | 1].val;
}
void build(int rt, int l, int r){
a[rt].l = l;
a[rt].r = r;
if(l == r){
cin >> a[rt].val;
return;
}
int mid = l + r >> 1;
build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
pushup(rt);
}
void update(int rt, int l, int r, ll k){
if(a[rt].l == a[rt].r){
a[rt].val += k;
return;
}
int mid = a[rt].l + a[rt].r >> 1;
if(l <= mid) update(rt << 1, l, r, k);
if(r > mid) update(rt << 1 | 1, l, r, k);
pushup(rt);
}
ll query(int rt, int l, int r){
if(l <= a[rt].l && a[rt].r <= r) return a[rt].val;
int mid = a[rt].l + a[rt].r >> 1;
ll sum = 0;
if(l <= mid) sum += query(rt << 1, l, r);
if(r > mid) sum += query(rt << 1 | 1, l, r);
return sum;
}
int main(){
cin >> n >> m;
build(1, 1, n);
while(m--){
int s, x, y;
ll k;
cin >> s >> x >> y;
if(s == 1){
cin >> k;
update(1, x, y, k); //让[x, y]每个范围全部+k
}
else cout << query(1, x, y) << endl; //查询[x, y]这个范围的所有数字
}
return 0;
}
懒标记
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct node{
int l, r;
ll val;
}a[400005];
ll tag[400005];
int n, m;
void pushup(int rt){
a[rt].val = a[rt << 1].val + a[rt << 1 | 1].val;
}
void build(int rt, int l, int r){
a[rt].l = l;
a[rt].r = r;
if(l == r){
cin >> a[rt].val;
return;
}
int mid = l + r >> 1;
build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
pushup(rt);
}
void pushdown(int rt){
if(tag[rt]){
tag[rt << 1] += tag[rt];
tag[rt << 1 | 1] += tag[rt];
int mid = a[rt].l + a[rt].r >> 1;
a[rt << 1].val += tag[rt] * (mid - a[rt].l + 1);
a[rt << 1 | 1].val += tag[rt] * (a[rt].r - mid);
tag[rt] = 0;
return;
}
}
void update(int rt, int l, int r, ll k){
if(l <= a[rt].l && a[rt].r <= r){ //如果当前点已经被包含
a[rt].val += k * (a[rt].r - a[rt].l + 1);
tag[rt] += k;
return;
}
pushdown(rt); //还账
int mid = a[rt].l + a[rt].r >> 1;
if(l <= mid) update(rt << 1, l, r, k);
if(r > mid) update(rt << 1 | 1, l, r, k);
pushup(rt);
}
ll query(int rt, int l, int r){
if(l <= a[rt].l && a[rt].r <= r) return a[rt].val;
int mid = a[rt].l + a[rt].r >> 1;
ll sum = 0;
pushdown(rt);
if(l <= mid) sum += query(rt << 1, l, r);
if(r > mid) sum += query(rt << 1 | 1, l, r);
return sum;
}
int main(){
cin >> n >> m;
build(1, 1, n);
while(m--){
int s, x, y;
ll k;
cin >> s >> x >> y;
if(s == 1){
cin >> k;
update(1, x, y, k); //让[x, y]每个范围全部+k
}
else cout << query(1, x, y) << endl; //查询[x, y]这个范围的所有数字
}
return 0;
}