计蒜客 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

题目来源

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;
}

 

你可能感兴趣的:(线段树)