AcWing 246. 区间最大公约数 [线段树,单点修改]
题目描述
给定一个长度为 NN 的数列 AA,以及 MM 条指令,每条指令可能是以下两种之一:
C l r d
,表示把 A[l],A[l+1],…,A[r]A[l],A[l+1],…,A[r] 都加上 dd。Q l r
,表示询问 A[l],A[l+1],…,A[r]A[l],A[l+1],…,A[r] 的最大公约数(GCD)。
对于每个询问,输出一个整数表示答案。
<br class="more">
输入格式
第一行两个整数 N,MN,M。
第二行 NN 个整数 A[i]A[i]。
接下来 MM 行表示 MM 条指令,每条指令的格式如题目描述所示。
输出格式
对于每个询问,输出一个整数表示答案。
每个答案占一行。
数据范围
N≤500000,M≤100000N≤500000,M≤100000,
1≤A[i]≤10181≤A[i]≤1018,
|d|≤1018|d|≤1018
输入样例:
5 5
1 3 5 7 9
Q 1 5
C 1 5 1
Q 1 5
C 3 3 6
Q 2 4
输出样例:
1
2
4
解题思路
思路1:直接维护区间修改的线段树
思路2:维护单点查询的线段树,我们主要讲这种思路
可以证明gcd(a1, a2,...,an)=gcd(a1, a2-a1,...,an-an-1),只需证明左式>=右式&&左式<=右式
证明完成后可以利用这一性质维护数组a的差分数组b, 那么对于a的区间修改可以转换成对b的单点修改,同时保证结果的正确性
对于查询gcd(al,...,ar),同样可以利用上面的性质转换为gcd(al, al+1-al,...,ar-ar-1),即gcd(al, bl+1, bl+2,...,br)
故而我们可以使用线段树维护区间和和区间gcd,代码如下
源代码
#include <bits/stdc++.h>
#define FastIO ios::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll> PII;
const char sp = 32, cr = 10;
const ll inf = 0x3f3f3f3f;
const ll N = 5e5 + 5, M = 1e5;
struct node {
ll l, r, g, s;
};
node tr[4 * N];
ll a[N], n, m;
ll gcd(ll a, ll b) {
return b ? gcd(b, a % b) : a;
}
void pushup(node& u, node& l, node& r) {
u.g = gcd(l.g, r.g);
u.s = l.s + r.s;
}
void pushup(ll u) {
pushup(tr[u], tr[2 * u], tr[2 * u + 1]);
}
void build(ll u, ll l, ll r) {
if (l == r) tr[u] = { l,r,a[l] - a[l - 1],a[l] - a[l - 1] };
else {
tr[u] = { l,r };
ll mid = (l + r) / 2;
build(2 * u, l, mid), build(2 * u + 1, mid + 1, r);
pushup(u);
}
}
void modify(ll u, ll p, ll v) {
if (tr[u].l == p && tr[u].r == p) tr[u].g += v, tr[u].s += v;
else {
ll mid = (tr[u].l + tr[u].r) / 2;
if (p > mid) modify(2 * u + 1, p, v);
else modify(2 * u, p, v);
pushup(u);
}
}
node query(ll u, ll l, ll r) {
if (l <= tr[u].l && tr[u].r <= r) return tr[u];
else {
ll mid = (tr[u].l + tr[u].r) / 2;
if (l <= mid && r > mid) {
node nl = query(2 * u, l, r);
node nr = query(2 * u + 1, l, r);
node res;
pushup(res, nl, nr);
return res;
}
else if (l <= mid) return query(2 * u, l, r);
else if (r > mid) return query(2 * u + 1, l, r);
}
}
int main() {
FastIO;
cin >> n >> m;
for (ll i = 1;i <= n;++i) cin >> a[i];
build(1, 1, n);
char f; ll l, r, d;
for (ll i = 0;i < m;++i) {
cin >> f >> l >> r;
if (f == 'Q') {
node nl = query(1, 1, l); //求a[l]
node nr = { 0,0,0,0 };
if (r + 1 <= n) nr = query(1, l + 1, r);
cout << abs(gcd(nl.s, nr.g)) << cr;
}
else {
cin >> d;
modify(1, l, d);
if (r + 1 <= n)
modify(1, r + 1, -d);
}
}
return 0;
}
登录后才能查看或发表评论, 立即 登录