HYSBZ - 5028 线段树 + GCD

题目链接
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);
      }
   }
}

猜你喜欢

转载自blog.csdn.net/deerly_/article/details/81637563