前言
不难的线段树题,散发着一股浓浓的套路的味道。
题目分析
首先可以知道 ”我们小学二年级就学过的“ 等差序列求和公式(这个真的是小学二年级的 (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; }