Ryuji doesn’t want to study - 计蒜客 41186 - Virtual Judge (vjudge.net)
题意
给定一个数组 a [ N ] a[N] a[N],有两种操作
- 给定 l , r l, r l,r, 查询 a [ l ] × L + a [ l + 1 ] × ( L − 1 ) + ⋯ + a [ r − 1 ] × 2 + a [ r ] a[l] \times L+a[l+1] \times(L-1)+\cdots+a[r-1] \times 2+a[r] a[l]×L+a[l+1]×(L−1)+⋯+a[r−1]×2+a[r] 的值
- 给定 x , y x, y x,y, 使 a [ x ] = y a[x]=y a[x]=y
有 N N N 个数据, M M M 种操作,对于每个操作 1 1 1 输出计算结果。
分析
把题目给出的求和式变形,得到
∑
i
=
l
r
a
i
×
(
r
−
i
+
1
)
=
∑
i
=
l
r
a
i
×
[
(
r
+
1
)
−
i
]
=
(
r
+
1
)
∑
i
=
l
r
a
i
−
∑
i
=
l
n
a
i
×
i
\begin{gathered} \sum_{i=l}^{r} a_{i} \times(r-i+1) \\ =\sum_{i=l}^{r} a_{i} \times[(r+1)-i] \\ =(r+1) \sum_{i=l}^{r} a_{i}-\sum_{i=l}^{n} a_{i} \times i \end{gathered}
i=l∑rai×(r−i+1)=i=l∑rai×[(r+1)−i]=(r+1)i=l∑rai−i=l∑nai×i
于是我们可以通过维护两个线段树来求解
Code
#include <bits/stdc++.h>
using namespace std;
#define LL long long
#define ULL unsigned long long
#define PII pair<int,int>
#define PLL pair<LL,LL>
#define PUU pair<ULL,ULL>
#define debug(a) cout << #a << " " << a << endl
#define fi first
#define se second
#define pb push_back
#define db double
const int maxn = 1500;
const int N = 1e6 + 7, M = N * 2;
const int inf = 0x3f3f3f3f;
const LL INF = 0xFFFFFFFFFF; //图接近 INT_MAX 时的初始化 判断时使用大于等于
const long long mod = 1e9 + 7;
inline long long read();
struct Node {
int l, r;
LL v; // 区间[l,r]中的最大值
} tr[N * 4], tr2[N * 4];
void pushup2(int u) { //由子节点的信息,算父节点的信息
tr2[u].v = tr2[u << 1].v + tr2[u << 1 | 1].v;
}
void build2(int u, int l, int r) {
tr2[u] = {l, r};
if (l == r) return;
int mid = (l + r) >> 1;
build2(u << 1, l, mid), build2(u << 1 | 1, mid + 1, r);
}
LL query2(int u, int l, int r) {
if (tr2[u].l >= l && tr2[u].r <= r) return tr2[u].v; //树中结点,已经完全被包含在[l,r]中
int mid = (tr2[u].l + tr2[u].r) >> 1;
LL ans = 0;
if (l <= mid) ans = query2(u << 1, l, r);
if (r > mid) ans = ans + query2(u << 1 | 1, l, r);
return ans;
}
void modify2(int u, int x, LL v) {
if (tr2[u].l == tr2[u].r) tr2[u].v = v;
else {
int mid = (tr2[u].l + tr2[u].r) >> 1;
if (x <= mid) modify2(u << 1, x, v);
else modify2(u << 1 | 1, x, v);
pushup2(u);
}
}
void pushup(int u) { //由子节点的信息,算父节点的信息
tr[u].v = tr[u << 1].v + tr[u << 1 | 1].v;
}
void build(int u, int l, int r) {
tr[u] = {l, r};
if (l == r) return;
int mid = (l + r) >> 1;
build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
}
LL query(int u, int l, int r) {
if (tr[u].l >= l && tr[u].r <= r) return tr[u].v; //树中结点,已经完全被包含在[l,r]中
int mid = (tr[u].l + tr[u].r) >> 1;
LL ans = 0;
if (l <= mid) ans = query(u << 1, l, r);
if (r > mid) ans = ans + query(u << 1 | 1, l, r);
return ans;
}
void modify(int u, int x, LL v) {
if (tr[u].l == tr[u].r) tr[u].v = v;
else {
int mid = (tr[u].l + tr[u].r) >> 1;
if (x <= mid) modify(u << 1, x, v);
else modify(u << 1 | 1, x, v);
pushup(u);
}
}
int n, q;
int main() {
// freopen("input.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
// ios::sync_with_stdio(false);
scanf("%d%d", &n, &q);
build(1, 1, n);
build2(1, 1, n);
for (int i = 1; i <= n; i++) {
LL x;
scanf("%lld", &x);
modify(1, i, x);
modify2(1, i, x * (LL)i);
}
for (int cas = 1; cas <= q; cas++) {
LL op, x, y;
scanf("%lld%lld%lld", &op, &x, &y);
if (op == 1) {
// debug((y + 1) * query(1, x, y));
// debug(query2(1, x, y));
LL ans = (y + 1) * query(1, x, y) - query2(1, x, y);
printf("%lld\n", ans);
}
else {
LL chmod = x * y;
modify(1, x, y);
modify2(1, x, chmod);
}
}
return 0;
}
inline LL read() {
char ch = getchar();
LL p = 1, data = 0;
while (ch < '0' || ch > '9') {
if (ch == '-')p = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
data = data * 10 + (ch ^ 48);
ch = getchar();
}
return p * data;
}