线段树——区间最大公约数

区间最大公约数

给定一个长度为N的数列A,以及M条指令,每条指令可能是以下两种之一:

1、“C l r d”,表示把 A[l],A[l+1],…,A[r] 都加上 d。

2、“Q l r”,表示询问 A[l],A[l+1],…,A[r] 的最大公约数(GCD)。

对于每个询问,输出一个整数表示答案。

输入格式
第一行两个整数N,M。

第二行N个整数A[i]。

接下来M行表示M条指令,每条指令的格式如题目描述所示。

输出格式
对于每个询问,输出一个整数表示答案。

每个答案占一行。

数据范围
N ≤ 500000 , M ≤ 100000 N≤500000,M≤100000 N500000,M100000
输入样例:
5 5
1 3 5 7 9
Q 1 5
C 1 5 1
Q 1 5
C 3 3 6
Q 2 4
输出样例:
1
2
4

题解:

首先回顾一个gcd的性质就是 g c d ( a , b ) = g c d ( a , b − a ) gcd(a,b)=gcd(a,b-a) gcd(a,b)=gcd(a,ba)
再写清楚一点就是 g c d ( a 1 , a 2 , a 3 . . . . a n ) = g c d ( a 1 , a 2 − a 1 , a 3 − a 2 . . . a n − a n − 1 ) gcd(a_1,a_2,a_3....a_n)=gcd(a_1,a_2-a_1,a_3-a_2...a_n-a_{n-1}) gcd(a1,a2,a3....an)=gcd(a1,a2a1,a3a2...anan1)
所以我们对于gcd的性质变成一个差分数组。对于差分数组我们的区间修改也就变成了单点修改。
对于我们区间求gcd也就变成了 g c d ( a l , g c d ( a l + 1 , a r ) ) gcd(a_l,gcd(a_{l+1},a_r)) gcd(al,gcd(al+1,ar))对于 a l a_l al就是我们1-l的前缀和,对于后面一坨就是后面一个区间的gcd。所以答案也就出来了。

#include 
#define int long long
using namespace std;
#define lson u<<1
#define rson u<<1|1
const int N=5e5+7;
int n,m,a[N];
struct Node{
    int l,r;
    long long sum,gcd;
}tr[N<<2];
long long  __gcd(long long a, long long b)
{
    return b ? __gcd(b, a % b) : a;
}
void pushup(Node &u,Node &l,Node &r)
{
    u.sum=l.sum+r.sum;
    u.gcd=__gcd(l.gcd,r.gcd);
}
void pushup(int u)
{
    pushup(tr[u],tr[lson],tr[rson]);
}
void build(int u,int l,int r)
{
    if(l==r){
        long long b=a[l]-a[l-1];
        tr[u]={l,r,b,b};
        return;
    }
    int mid=l+r>>1;
    tr[u]={l,r};
    build(lson,l,mid);
    build(rson,mid+1,r);
    pushup(u);
}
Node query(int u,int l,int r)
{
    if(tr[u].l>=l&&tr[u].r<=r){
        return tr[u];
    }
    int mid=tr[u].l+tr[u].r>>1;
    if(r<=mid) return query(lson,l,r);
    else if(l>mid) return query(rson,l,r);
    else{
        auto left=query(lson,l,r);
        auto right=query(rson,l,r);
        Node res;
        pushup(res,left,right);
        return res;
    }
}
void modify(int u,int x,int c)
{
    if(tr[u].l==x&&tr[u].r==x){
        long long b=tr[u].sum+c;
        tr[u]={x,x,b,b};
        return ;
    }
    int mid=tr[u].l+tr[u].r>>1;
    if(x<=mid) modify(lson,x,c);
    else if(x>mid) modify(rson,x,c);
    pushup(u);
}

signed main(){
    scanf("%lld%lld",&n,&m);
    for(int i=1;i<=n;i++) scanf("%lld",a+i);
    build(1,1,n);
    for(int i=1;i<=m;i++){
        char op[3];
        scanf("%s",op);
        if(*op=='Q'){
            int l,r; scanf("%lld%lld",&l,&r);
            auto left=query(1,1,l);
            auto right=query(1,l+1,r);
            printf("%lld\n",abs(__gcd(left.sum,right.gcd)));
        }else{
            int l,r,c;
            scanf("%lld%lld%lld",&l,&r,&c);
            modify(1,l,c);
            if(r+1<=n) modify(1,r+1,-c);
        }
    }
    return 0;
}

你可能感兴趣的:(数据结构)