线段树区间gcd

小阳的贝壳

题意:
操作 1 l 到 r 的区间加上x
操作2 l到 r 相邻两个差值的绝对值最大 l==r输出0
操作3 l 到 r 的gcd
难点就是是gcd 要想求区间能修改的gcd 你必须要知道一些知识
gcd(a,b)=gcd(a,b-a). gcd(a,b,c)=gcd(a,b-a,c-a) 以此类推
然后只要线段树 维护 相邻两个的差值就可以了 当遇到 操作1
时 由于一个区间的加上相同的数 只有 第一个 和最后一个值改变了因此只有单点修改第一个 与最后一个就行了 即 第一个加上x 最后一个的下一个减去x
代码

#include
using namespace std;
const int N=1e5+7;
int n,Q,p[N],h[N];
int add[N];

int gcd(int a,int b){return b?gcd(b,a%b):a;}

struct node{
    int v,g,maxn;
}tree[4*N];

#define lson 2*node
#define rson 2*node+1
#define m (l+r)/2

void build(int l,int r,int node){
    if(l==r){
        tree[node].v=p[l];
        tree[node].g=h[l];
        tree[node].maxn=h[l];
        return;
    }
    build(l,m,lson);
    build(m+1,r,rson);
    tree[node].g=gcd(tree[lson].g,tree[rson].g);
    tree[node].maxn=max(abs(tree[lson].maxn),abs(tree[rson].maxn));
}

void push_down(int node){
    if(add[node]){
        tree[lson].v+=add[node];
        tree[rson].v+=add[node];
        add[lson]+=add[node];
        add[rson]+=add[node];
        add[node]=0;
    }
}

void update(int v,int ql,int qr,int l,int r,int node){
    if(ql<=l&&qr>=r){
        tree[node].v+=v;
        add[node]+=v;
        return;
    }
    push_down(node);
    if(ql<=m)update(v,ql,qr,l,m,lson);
    if(qr>m)update(v,ql,qr,m+1,r,rson);
}

void upgcd(int v,int pos,int l,int r,int node){
    if(l==r){
        tree[node].g+=v;
        tree[node].maxn+=v;
        return;
    }
    if(pos<=m)upgcd(v,pos,l,m,lson);
    else upgcd(v,pos,m+1,r,rson);
    tree[node].g=gcd(tree[lson].g,tree[rson].g);
    tree[node].maxn=max(abs(tree[lson].maxn),abs(tree[rson].maxn));
}

int query(int ql,int qr,int l,int r,int node){
    if(ql<=l&&qr>=r) return tree[node].g;
    int ans=0;
    if(ql<=m)ans=gcd(ans,query(ql,qr,l,m,lson));
    if(qr>m)ans=gcd(ans,query(ql,qr,m+1,r,rson));
    return ans;
}
int querymax(int ql,int qr,int l,int r,int node){
    if(ql>qr)return 0;
    if(ql<=l&&qr>=r){
        return abs(tree[node].maxn);
    }
    int ans=0;
    if(ql<=m)ans=max(ans,querymax(ql,qr,l,m,lson));
    if(qr>m)ans=max(ans,querymax(ql,qr,m+1,r,rson));
    return ans;
}

int queryvalue(int pos,int l,int r,int node){
    if(l==r)return tree[node].v;
    push_down(node);
    if(pos<=m)return queryvalue(pos,l,m,lson);
    return queryvalue(pos,m+1,r,rson);
}


int main(){
    scanf("%d%d",&n,&Q);
    for(int i=1;i<=n;i++){
        scanf("%d",&p[i]);
        h[i]=p[i]-p[i-1];
    }
    build(1,n,1);
    int q,l,r,x;
    while(Q--){
        scanf("%d%d%d",&q,&l,&r);
        if(q==1){
            scanf("%d",&x);
            update(x,l,r,1,n,1);
            upgcd(x,l,1,n,1);
            if(r+1<=n)upgcd(-x,r+1,1,n,1);
        }else if(q==2){
            printf("%d\n",querymax(l+1,r,1,n,1));
        }else if(q==3){
            if(l==r)printf("%d\n",queryvalue(l,1,n,1));
            else{
                int ans=queryvalue(l,1,n,1);
                ans=gcd(ans,query(l+1,r,1,n,1));
                printf("%d\n",abs(ans));
            }
        }
    }
}


你可能感兴趣的:(线段树区间gcd)