Ryuji is not a good student, and he doesn't want to study. But there are n books he should learn, each book has its knowledge a[i]a[i].
Unfortunately, the longer he learns, the fewer he gets.
That means, if he reads books from ll to rr, he will get 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] (LL is the length of [ ll, rr ] that equals to r - l + 1r−l+1).
Now Ryuji has qq questions, you should answer him:
11. If the question type is 11, you should answer how much knowledge he will get after he reads books [ ll, rr ].
22. If the question type is 22, Ryuji will change the ith book's knowledge to a new value.
First line contains two integers nn and qq (nn, q \le 100000q≤100000).
The next line contains n integers represent a[i]( a[i] \le 1e9)a[i](a[i]≤1e9) .
Then in next qq line each line contains three integers aa, bb, cc, if a = 1a=1, it means question type is 11, and bb, ccrepresents [ ll , rr ]. if a = 2a=2 , it means question type is 22 , and bb, cc means Ryuji changes the bth book' knowledge to cc
For each question, output one line with one integer represent the answer.
样例输入复制
5 3
1 2 3 4 5
1 1 3
2 5 0
1 4 5
样例输出复制
10
8
题目来源
ACM-ICPC 2018 徐州赛区网络预赛
题意:吉老师不喜欢读书,所以他有 n 本书,书本编号从 1 到 n,每本书有一个价值
现在吉老师有两个操作,一个是修改一本书的价值,另一个是选择一个区间
然后求按顺序读完这个区间里所有书获得的价值,获取价值的规则如下:
如果这个区间的长度为 x ,那么总价值为:x * (第一本书价值) + (x - 1) * (第二本书价值) + ... + 1 * (最后一本书的价值)
思路:
维护两个值,一个是区间价值之和(不乘系数的),另一个是带有系数的, n 本书,系数就从 n 到 1
例如我们总共有 7 本书,价值分别为 5 1 3 6 8 4 9 的话
那么 sum1 维护 5 1 3 6 8 4 9 的区间和
sum2 维护 (5 * 7) (1 * 6) (3 * 5) (6 * 4) (8 * 3) (4 * 2) (9 * 1) 的区间和
用线段树维护和更新
求 [ l , r ] 的答案的时候,从 sum1 取出区间 l 到 r 的 ans,记为 ans 1
再从 sum2 取出 区间 l 到 r 的 ans 记为 ans2
我们可以发现取出来的这两个值都不是答案,ans2 显然是 大于等于 答案的,并且差值是 ans1 的倍数,至于这个倍数是多少,写一组样例你就可以看得出来,差的倍数 是 n - r
所以答案 = ans2 - ans1 * (n - r)
代码如下:
#include
using namespace std;
#define ll long long
const int maxn = 1e5 + 5;
struct node {
ll l,r;
ll sum1, sum2;
} tree[maxn * 4];
struct Ans{
ll ans1, ans2;
Ans(){}
Ans(ll _ans1, ll _ans2){
ans1 = _ans1;
ans2 = _ans2;
}
Ans operator + (const Ans &b)const{
return Ans(ans1 + b.ans1, ans2 + b.ans2);
}
};
ll n;
ll val[maxn];
void push_up(ll rt) {
tree[rt].sum1 = tree[rt << 1].sum1 + tree[(rt << 1) | 1].sum1;
tree[rt].sum2 = tree[rt << 1].sum2 + tree[(rt << 1) | 1].sum2;
}
void build(ll l, ll r, ll rt) {
tree[rt].l = l;
tree[rt].r = r;
if(l == r) {
tree[rt].sum1 = val[l];
tree[rt].sum2 = val[l] * (n - l + 1);
return ;
}
ll mid = (l + r) >> 1;
build(l, mid, rt << 1);
build(mid + 1, r, (rt << 1) | 1);
push_up(rt);
}
void update(ll p, ll v, ll rt) {
if(tree[rt].l == tree[rt].r && tree[rt].r == p) {
tree[rt].sum1 = v;
tree[rt].sum2 = v * (n - p + 1);
return ;
}
ll mid = (tree[rt].l + tree[rt].r) >> 1;
if(p <= mid) {
update(p, v, rt << 1);
} else {
update(p, v, (rt << 1) | 1);
}
push_up(rt);
}
Ans query(ll l, ll r, ll rt) {
if(l <= tree[rt].l && r >= tree[rt].r) {
return Ans(tree[rt].sum1, tree[rt].sum2);
}
ll mid = (tree[rt].l + tree[rt].r) >> 1;
Ans ans = Ans(0, 0);
if(l <= mid) {
ans = ans + query(l, r, rt << 1);
}
if(r > mid) {
ans = ans + query(l, r, (rt << 1) | 1);
}
return ans;
}
int main() {
ll m,opt,x,y;
scanf("%lld %lld",&n,&m);
for(ll i = 1; i <= n; i++) {
scanf("%lld", &val[i]);
}
build(1, n, 1);
while(m--) {
scanf("%lld %lld %lld", &opt, &x, &y);
if(opt == 2){
update(x, y, 1);
}else if(opt == 1){
Ans ans = query(x, y, 1);
printf("%lld\n",ans.ans2 - ans.ans1 * (n - y));
}
}
return 0;
}