1. 程式人生 > >計蒜客 Ryuji doesn't want to study(2018 ICPC 徐州 網路賽 )線段樹

計蒜客 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;
}