計蒜客 Ryuji doesn't want to study(2018 ICPC 徐州 網路賽 )線段樹
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.
Input
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
Output
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
題目來源
題意:吉老師不喜歡讀書,所以他有 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<bits/stdc++.h>
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;
}