题目:小Z的加油店 HYSBZ-5028
前置技能:
-
性质:
- 线段树单点更新区间查询
具体实现:
- 建立线段树,并维护差分序列的区间 和区间和
- 更新操作: 更新 区间的所有值 ,此时我们会发现序列的差分并不会改变,改变的只有第一个数字,所以我们只需要单点更新 ,然后如果 存在元素的话,那么 ,因为我我们给 加了x,序列差分会影响该区间后面一个元素的差分
- 查询操作:正常的查询区间,然后统计答案。
- 统计答案:
- 对4补充为什么是前缀和,因为维护的是原序列的差分,所以相当于维护的是 ,因此我们发现
AC代码:
#include <iostream>
#include <stdio.h>
#include <set>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <vector>
#include <cmath>
#include <stack>
#include <map>
#include <iomanip>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 100005;
const ll inf = 0x3f3f3f3f;
typedef long double ld;
#define met(a, b) memset(a, b, sizeof(a))
#define rep(i, a, b) for(int i = a; i <= b; i++)
#define per(i, a, b) for(int i = a; i >= b; i--)
#define fi first
#define se second
#define pb push_back
#define mp make_pair
inline ll mul(ll x, ll y, ll mod) {ll res = (x * y - (ll)(ld)(x / mod * y + 1e-8) * mod); return res < 0 ? res + mod : res;}
const double PI = acos(-1.0);
const int mod = 1e9+7;
ll qPow(ll base, ll n) {ll res = 1; while(n) {if(n & 1) res = (res * base) % mod; base = (base * base) % mod; n >>= 1;} return res % mod;}
ll gcd(ll a, ll b) {
if(a < 0) a = -a;
if(b < 0) b = -b;
return b == 0 ? a : gcd(b, a % b);
}
int n, q, a[maxn];
struct NODE{
int gd, sum, l, r;
} treeNode[maxn * 4];
void pushUp(int root) {
treeNode[root].gd = gcd(treeNode[root << 1].gd, treeNode[root << 1 | 1].gd);
treeNode[root].sum = treeNode[root << 1].sum + treeNode[root << 1 | 1].sum;
}
void build(int root, int l, int r) {
treeNode[root].l = l;
treeNode[root].r = r;
if(l == r) {
treeNode[root].gd = a[l];
treeNode[root].sum = a[l];
return;
}
int mid = (l + r) >> 1;
build(root << 1, l, mid);
build(root << 1 | 1, mid + 1, r);
pushUp(root);
}
void update(int root, int pos, int x) {
if(treeNode[root].l == treeNode[root].r) {
treeNode[root].gd += x;
treeNode[root].sum += x;
return;
}
int mid = (treeNode[root].l + treeNode[root].r) >> 1;
if(pos <= mid) update(root << 1, pos, x);
else update(root << 1 | 1, pos, x);
pushUp(root);
//if()
}
int queryGcd(int root, int l, int r) {
if(l > r) return 0;
if(treeNode[root].l == l && treeNode[root].r == r) {
return treeNode[root].gd;
}
int mid = (treeNode[root].l + treeNode[root].r) >> 1;
if(r <= mid) {
return queryGcd(root << 1, l, r);
} else if(l > mid) {
return queryGcd(root << 1 | 1, l, r);
} else {
return gcd(queryGcd(root << 1, l, mid), queryGcd(root << 1 | 1, mid + 1, r));
}
}
int querySum(int root, int l, int r) {
if(treeNode[root].l == l && treeNode[root].r == r) {
return treeNode[root].sum;
}
int mid = (treeNode[root].l + treeNode[root].r) >> 1;
if(r <= mid) return querySum(root << 1, l, r);
else if(l > mid) return querySum(root << 1 | 1, l, r);
else {
return querySum(root << 1, l, mid) + querySum(root << 1 | 1, mid + 1, r);
}
}
int main() {
while(~scanf("%d%d", &n, &q)) {
a[0] = 0;
rep(i, 1, n) {
scanf("%d", &a[i]);
}
per(i, n, 2) {
a[i] -= a[i - 1];
}
build(1, 1, n);
while(q--) {
int com, l, r;
scanf("%d%d%d", &com, &l, &r);
if(com == 1) {
printf("%lld\n", abs(gcd(queryGcd(1,l+1,r),querySum(1,1,l))));
} else {
int x;
scanf("%d", &x);
update(1, l, x);
if(r < n) update(1, r + 1, -x);
}
}
}
return 0;
}