题解:P10463 Interval GCD

· · 题解

前置知识:线段树以及 \gcd 的性质相关。

第一眼看到区间加,肯定想到懒标记。但第二眼再看到区间 \gcd,发现必须暴力更新叶节点。

怎么解决?转换成单点修改不就解决了么!

这就要用到这么一个性质:

\gcd(a_l,a_{l + 1},\cdots,a_{r - 1},a_r) = \gcd(a_l,a_{l + 1} - a_l,\cdots,a_{r - 1} - a_{r - 2},a_r - a_{r - 1})

发现右边那一串不就是 a 的差分数组吗!

既然是差分数组,那么在原数组上的区间修改不就相当于差分数组上的单点修改吗!

这样我们就成功地把区间修改转化成了单点修改。

具体实现上需要注意,线段树只能查询 \gcd(a_{l + 1} - a_l,\cdots,a_{r - 1} - a_{r - 2},a_r - a_{r - 1}),计这个结果为 ans,那么真正的答案应该是 \gcd(a_l,ans)

```cpp #include<bits/stdc++.h> #define int long long #define mid ((l + r) >> 1) #define lchild (root << 1) #define rchild ((root << 1) + 1) using namespace std; const int N = 5e5 + 9; int n,m; int a[N],b[N],c[N]; string op;int l,r,d; struct node{ int val; } t[N << 2]; int GCD(int a,int b){ return b ? GCD(b,a % b) : abs(a); } bool in_range(int l,int r,int L,int R){ return L <= l && r <= R; } bool out_range(int l,int r,int L,int R){ return l > R || r < L; } void push_up(int root){ t[root].val = GCD(t[lchild].val,t[rchild].val); } void build(int root,int l,int r){ if(l == r){ t[root].val = b[l]; return; } build(lchild,l,mid); build(rchild,mid + 1,r); push_up(root); } void update(int root,int l,int r,int k,int v){ if(r < k || l > k) return; if(l == r){ t[root].val += v; return; } if(k <= mid) update(lchild,l,mid,k,v); else update(rchild,mid + 1,r,k,v); push_up(root); } int query(int root,int l,int r,int L,int R){ if(out_range(l,r,L,R)) return 0; if(in_range(l,r,L,R)) return t[root].val; return GCD(query(lchild,l,mid,L,R),query(rchild,mid + 1,r,L,R)); } int lowbit(int x){ return x & (-x); } int sum(int x){ int ret = 0; for(int i = x;i;i -= lowbit(i)) ret += c[i]; return ret; } void add(int x,int y){ for(int i = x;i <= n;i += lowbit(i)) c[i] += y; } signed main(){ ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); cin >> n >> m; for(int i = 1;i <= n;i++){ cin >> a[i]; b[i] = a[i] - a[i - 1]; add(i,b[i]); } build(1,1,n); while(m--){ cin >> op >> l >> r; if(op == "C"){ cin >> d; update(1,1,n,l,d); update(1,1,n,r + 1,-d); add(l,d); add(r + 1,-d); } else cout << GCD(sum(l),query(1,1,n,l + 1,r)) << '\n'; } return 0; } ```