这是一道线段树的题目,,,
废话就不多说了。。
思路:
用两个线段树去维护,第一个线段树①的根节点是初始数据,第二个线段树②是假设从[1,n]的查询所得到的值,每个根节点放的就是
当前数据×总长度(n - -)的值
还是举个栗子吧:在1,2,3,4,5 这组数据中
线段树①的根节点存放的就是1,2,3,4,5
线段树②的根节点存放的就是 1*5,2*4,3*3,4*2,5*1
实际查询的区间结果如[1,3]则为: (1*5+2*4+3*3)而这一片段多算了[1,3]这个区间两次(因为之前是按长度n=5去算的,而现在区间长度为3)所以要减去原始区间两次(5-3)
H题 Ryuji doesn’t want to study
#include<iostream>
#include<stdio.h>
#include<string.h>
#pragma warning (disable :4996);
#include<algorithm>
using namespace std;
#define ll long long
ll n, m;
ll t[100100 *4];
ll t1[100100 * 4];
ll sum = 0;
ll sum1 = 0;
ll ren = 0;
ll num=0;
void build(ll l, ll r, ll rt) {
if (l == r) {
scanf("%lld", &t1[rt]);
t[rt] = t1[rt] * (ren--);
return;
}
ll mid = (l + r) >> 1;
build(l, mid, rt << 1);
build(mid + 1, r, rt << 1 | 1);
t[rt] = t[rt << 1] + t[rt << 1 | 1];
t1[rt] = t1[rt << 1] + t1[rt << 1 | 1];
}
//单一
void update(ll l, ll r, ll rt, ll pos, ll val) {
if (l == r && l == pos) {
t1[rt] = val;
return;
}
ll mid = (l + r) >> 1;
if (mid >= pos)update(l, mid, rt << 1, pos, val);
if (mid<pos) update(mid + 1, r, rt << 1 | 1, pos, val);
t1[rt] = t1[rt << 1] + t1[rt << 1 | 1];
}
void query(ll l, ll r, ll rt, ll L, ll R) {
if (l >= L && r <= R) {
sum1 += t1[rt];
return;
}
ll mid = (l + r) >> 1;
if (mid >= L)query(l, mid, rt << 1, L, R);
if (mid < R)query(mid + 1, r, rt << 1 | 1, L, R);
return;
}
//乘积
void _update(ll l, ll r, ll rt, ll pos, ll val) {
if (l == r && l == pos) {
t[rt] = val*(n-pos+1);
return;
}
ll mid = (l + r) >> 1;
if (mid >= pos)_update(l, mid, rt << 1, pos, val);
if (mid<pos) _update(mid + 1, r, rt << 1 | 1, pos, val);
t[rt] = t[rt << 1] + t[rt << 1 | 1];
}
void _query(ll l, ll r, ll rt, ll L, ll R) {
if (l >= L && r <= R) {
sum += t[rt];
return;
}
ll mid = (l + r) >> 1;
if (mid >= L)_query(l, mid, rt << 1, L, R);
if (mid < R)_query(mid + 1, r, rt << 1 | 1, L, R);
return;
}
int main() {
ll a, b, c;
scanf("%lld%lld", &n, &m);
ren = n;
memset(t, 0, sizeof(t));
build(1, n, 1);
long long x;
for (ll i = 0; i <m; i++) {
scanf("%lld%lld%lld", &x,&a,&b);
if (x == 1) {
_query(1, n, 1, a, b);
query(1, n, 1, a, b);
sum1 *= (n - b);
printf("%lld\n", sum-sum1);
sum = sum1=0;
}
else if (x == 2) {
_update(1, n, 1, a, b);
update(1, n, 1,a, b);
}
}
return 0;
}
G题好像也是线段树。。先把坑留着吧,
G题: