题目链接
Problem
说不清楚,简化之后就是两种操作
1 求[l,r]区间的gcd
2 给[l, r]区间每个元素 + v
Input
3 4
2 3 4
1 1 3
2 2 2 1
1 1 3
1 2 3
Output
1 2 4
Ideas
![]()
首先要明白这里,gcd可以进行这样的差分。
这样对[L, R]区间加, 只要L处加, R+1处减就可以了。
gcd(a1, a2 - a1, a3 - a2, a4 - a3, a5 - a4)
因为当对a1, a2, ….a4处加v时, a1加上了v, 第二项a2 - a1是不变的,a3 - a2,a4 - a3也是不变,的,a5 - a4会少了一个v,所以只要L处加, R+1处减就可以了。
当我们求gcd(l, l + 1, …r)的时候,只要求gcd(al, al+1 - al, a(l + 2) - a(l +1) ….ar - a(r - 1));
所以我们求gcd[l, r]只要求下1~l-1的和, 然后求gcd[l + 1, r]即可,因为1~l-1的和就是al。
code
#include <bits/stdc++.h>
using namespace std;
#define lson root << 1
#define rson root << 1 | 1
#define MID int mid = (l + r) / 2
typedef long long ll;
const int maxn = 1e5 + 100;
struct node {
ll g;
ll sum;
} tree[maxn << 2];
ll data[maxn];
void build(int root, int l, int r, int pos, ll v) {
if(pos < l || pos > r) return ;
if(l == r) {
tree[root] = (node) {v, v};
return ;
}
MID;
build(lson, l, mid, pos, v);
build(rson, mid + 1, r, pos, v);
ll tg = __gcd(tree[lson].g, tree[rson].g);
tree[root] = (node) {tg, tree[lson].sum + tree[rson].sum};
}
void Insert(int root, int l, int r, int pos, ll v) {
if(pos < l || pos > r) return ;
if(l == r) {
tree[root].g += v;
tree[root].sum += v;
return ;
}
MID;
Insert(lson, l, mid, pos, v);
Insert(rson, mid + 1, r, pos, v);
ll tg = __gcd(tree[lson].g, tree[rson].g);
ll tsum = tree[lson].sum + tree[rson].sum;
tree[root] = (node) {tg, tsum};
}
ll query(int root, int l, int r, int ul, int ur, bool flag) {
if(ul > r || ur < l) return 0;
if(ul <= l && r <= ur) return (flag ? tree[root].g : tree[root].sum);
MID;
if(flag)
return __gcd(query(lson, l, mid, ul, ur, flag), query(rson, mid + 1, r, ul, ur, flag));
else return query(lson, l, mid, ul, ur, flag) + query(rson, mid + 1, r, ul, ur, flag);
}
int main()
{
int n, m;
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i++) {
scanf("%lld", &data[i]);
int v = data[i] - data[i - 1];
build(1, 1, n, i, v);
}
for(int i = 0; i < m; i++) {
int p, l, r, x;
scanf("%d %d %d", &p, &l, &r);
if(l > r) swap(l, r);
if(p == 1) {
ll v1 = query(1, 1, n, 1, l, false);
ll v2 = query(1, 1, n, l + 1, r, true);
ll v = __gcd(v1, v2);
printf("%lld\n", abs(v));
}
else {
scanf("%d", &x);
Insert(1, 1, n, l, x);
if(r + 1 <= n)
Insert(1, 1, n, r + 1, -x);
}
}
}