前言
不难的线段树题,散发着一股浓浓的套路的味道。
题目分析
首先可以知道 ”我们小学二年级就学过的“ 等差序列求和公式(这个真的是小学二年级的 (doge
然后对于本题的操作一进行分析:
不妨假设修改的区间为:
倘若这个区间包含了一个线段树节点
, 这个节点的区间左端点为
, 区间右端点为
,
那么节点
的区间和就是
(首项 加 末项) * 项数 / 2 这个公式我们耳熟能详
这里的 首项 就是
, 末项 就是
,项数 就是
。
整理一下就是 :
那么很明显,我们需要记录每次修改的区间左端点 以及给定的
, 于是我们在线段树的懒标记中开两个数组分别记录每次修改给定的
以及区间左端点即可。然后在每次进行修改操作之前都下传标记即可。
想必操作二应该就不用细说了吧,应该都会,吧?
Code
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define mid ((L[x] + R[x]) >> 1)
inline int read() {
int x = 0 , flag = 1;
char ch = getchar();
for( ; ch > '9' || ch < '0' ; ch = getchar()) if(ch == '-') flag = -1;
for( ; ch >= '0' && ch <= '9'; ch = getchar()) x = (x << 3) + (x << 1) + ch - '0';
return x * flag;
}
typedef long long LL;
const int MAXN = 2e5 + 50;
int n, Q; // n 表示序列长度,Q 表示询问 和 修改的次数
int A[MAXN]; // 原始数列
struct SegmentTree {
int L[MAXN << 2], R[MAXN << 2],laz[MAXN << 2], tl[MAXN << 2];//laz 记录的是修改的 k,tl 表示修改的左端点
LL sum[MAXN << 2];
void update(int x) {sum[x] = sum[x << 1] + sum[x << 1 | 1];}
void build(int x, int l, int r) {
L[x] = l, R[x] = r; laz[x] = 0;
if(l == r) {sum[x] = A[l]; return ;}
build(x << 1, l, mid);
build(x << 1 | 1, mid + 1 , r);
update(x);
return ;
}
void ad(int x, int k ,int l) { // k 如题意所述,x 表示修改的线段树节点编号,l 表示修改的左端点
int len = R[x] - L[x] + 1;//区间长度
sum[x] = (LL)len * (LL)(L[x] + R[x] + 2 * (k - l)) / 2; //等差序列求和公式求出区间和
laz[x] = k, tl[x] = l; // 懒标记记录
return ;
}
void pushdown(int x) {
if(!laz[x]) return ;
ad(x << 1, laz[x], tl[x]);
ad(x << 1 | 1, laz[x], tl[x]);
laz[x] = 0, tl[x] = 0; //两个都要清空,注意一下
return ;
}
void change(int x, int l, int r, int k) {
if(L[x] >= l && R[x] <= r) {
ad(x, k, l);
return ;
}
pushdown(x);
if(l <= mid) change(x << 1, l, r, k);
if(r > mid) change(x << 1 | 1, l, r, k);
update(x);
return ;
}
LL GetSum(int x, int l, int r) { //常规区间求和即可
LL S = 0;
if(L[x] >= l && R[x] <= r) return sum[x];
pushdown(x);
if(l <= mid) S += GetSum(x << 1, l, r);
if(r > mid) S += GetSum(x << 1 | 1, l, r);
return S;
}
} T;
signed main() {
n = read(), Q = read();
for(int i = 1 ; i <= n ; i ++) A[i] = read();
T.build(1, 1, n);
while(Q --) {
int op = read(),l = read(), r = read();
if(op == 1) T.change(1, l, r, read());
else printf("%lld\n", T.GetSum(1, l, r));
}
return 0;
} 
京公网安备 11010502036488号