线段树带修改求区间gcd

题目:小Z的加油店 HYSBZ-5028


前置技能:

  1. g c d 性质:
    g c d ( a 1 , a 2 , a 3 , . . . . . . , a n 2 , a n 1 , a n ) = g c d ( a 1 , a 2 a 1 , a 3 a 2 , . . . . . . , a n 1 a n 2 , a n a n 1 )
  2. 线段树单点更新区间查询

具体实现:

  1. 建立线段树,并维护差分序列的区间 g c d 和区间和
  2. 更新操作: ( l , r , x ) 更新 ( l , r ) 区间的所有值 + x ,此时我们会发现序列的差分并不会改变,改变的只有第一个数字,所以我们只需要单点更新 a l ,然后如果 r + 1 存在元素的话,那么 a r + 1 = a r + 1 x ,因为我我们给 [ l , r ] 加了x,序列差分会影响该区间后面一个元素的差分
  3. 查询操作:正常的查询区间,然后统计答案。
  4. 统计答案: a n s = g c d ( g c d ( a l + 1 , a l + 2 , . . . , a r ) , i = 1 l a i )
  5. 对4补充为什么是前缀和,因为维护的是原序列的差分,所以相当于维护的是 a 1 , a 2 a 1 , a 3 a 2 , . . . , a l a l 1 . . . . . . . ,因此我们发现 ( i = 1 l a i ) = a l

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;
}

猜你喜欢

转载自blog.csdn.net/m0_38081836/article/details/81608721