线段树 区间加 gcd 差分
生活随笔
收集整理的這篇文章主要介紹了
线段树 区间加 gcd 差分
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
小陽的貝殼
?
如果線段樹要維護區間gcd 這個很簡單,但是如果有了區間加,維護gcd 就比較麻煩了。
這個首先可以證明的是 gcd(x,y,z)=gcd(x,y-x,z-y)? ?這個可以推到 n 個
證明過程傳送門
這個就和差分扯上關系了? ?可以看一下差分 差分傳送門
上面的這兩個博客基本上告訴我們這兩個題目怎么寫了。
?
首先我們對于每一個數進行處理,把這個數變成差分的形式,
因為最后的結果我們要 gcd(x,y-x,z-y) 所以我們要求和,還有求gcd ,這個就會有兩個查詢,一個查詢sum,一個查詢gcd
你看了差分的博客后你就發現,如果我們要給一段區間整體加上一個值,這個區間更新可以轉化成差分的單點更新。
然后就是區間差值最大,這個很好求,因為我們每一個數本來放進去的就是區間的差分,所以這個相當于在求最大值。只是注意邊界。
?
#include <cstdio> #include <cstdlib> #include <cstring> #include <queue> #include <vector> #include <algorithm> #include <string> #include <iostream> #include <map> #define inf 0x3f3f3f3f #define inf64 0x3f3f3f3f3f3f3f3f using namespace std; const int maxn = 2e5 + 10; int a[maxn]; struct node {int l, r;int max, sum, val; }tree[maxn*4];int gcd(int a,int b) {return b == 0 ? a : gcd(b, a%b); }void push_up(int id) {tree[id].max = max(abs(tree[id << 1].max), abs(tree[id << 1 | 1].max));tree[id].sum = tree[id << 1 | 1].sum + tree[id << 1].sum;tree[id].val = gcd(tree[id << 1].val, tree[id << 1 | 1].val); }void build(int id,int l,int r) {tree[id].l = l;tree[id].r = r;if(l==r){tree[id].sum = tree[id].val = a[l];tree[id].max = abs(a[l]);return;}int mid = (l + r) >> 1;build(id << 1, l, mid);build(id << 1 | 1, mid + 1, r);push_up(id); }int query_sum(int id,int x,int y) {int l = tree[id].l;int r = tree[id].r;if(x<=l&&y>=r){return tree[id].sum;}int ans = 0;int mid = (l + r) >> 1;if (x <= mid) ans += query_sum(id << 1, x, y);if (y > mid) ans += query_sum(id << 1 | 1, x, y);return ans; }int query_val(int id,int x,int y) {int l = tree[id].l;int r = tree[id].r;if(x<=l&&y>=r){return tree[id].val;}int ans = 0;int mid = (l + r) >> 1;if (x <= mid) ans = gcd(ans, query_val(id << 1, x, y));if (y > mid) ans = gcd(ans, query_val(id << 1 | 1, x, y));return ans; }int query_max(int id,int x,int y) {int l = tree[id].l;int r = tree[id].r;if(x<=l&&y>=r){return tree[id].max;}int ans = 0;int mid = (l + r) >> 1;if (x <= mid) ans = max(ans, query_max(id << 1, x, y));if (y > mid) ans = max(ans, query_max(id << 1 | 1, x, y));return ans; }void update(int id,int pos,int x) {int l = tree[id].l;int r = tree[id].r;if(l==r){tree[id].sum += x;tree[id].val += x;tree[id].max = abs(tree[id].val);return;}int mid = (l + r) >> 1;if (pos <= mid) update(id << 1, pos, x);else update(id << 1 | 1, pos, x);push_up(id); }int main() {int n, m;scanf("%d%d", &n, &m);for (int i = 1; i <= n; i++) scanf("%d", &a[i]);for (int i = n; i >= 1; i--) a[i] = a[i] - a[i - 1];build(1, 1, n);while (m--) {int opt, l, r, x;scanf("%d", &opt);if(opt==1){scanf("%d%d%d", &l, &r, &x);if (l > r) swap(l, r);update(1, l, x);if(r+1<=n) update(1, r + 1, -x);}if(opt==2){scanf("%d%d", &l, &r);if (l > r) swap(l, r);int ans = 0;if(l!=r) ans = query_max(1, l + 1, r);printf("%d\n", ans);}if(opt==3){scanf("%d%d", &l, &r);if (l > r) swap(l, r);int ans = 0;int ex1 = query_sum(1, 1, l);int ex2 = query_val(1, l + 1, r);if (l == r) ans = ex1;else ans = abs(gcd(ex1, ex2));printf("%d\n", ans);}// if(opt==4)// {// scanf("%d", &l);// printf("%d\n", query_sum(1, 1, l));// } }return 0; } gcd 線段樹 差分?
轉載于:https://www.cnblogs.com/EchoZQN/p/11202434.html
總結
以上是生活随笔為你收集整理的线段树 区间加 gcd 差分的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux——自定义服务命令
- 下一篇: 数据结构之单项链表的操作