大致题意:
一个序列,可以执行两种操作。

  • 图片说明 对区间图片说明 内的元素依次对x取图片说明 ,然后将结果赋值给图片说明 .
  • 图片说明 求区间元素和。

图片说明

分析:这道题跟区间开方思路类似。
每次对一个区间进行gcd的话一般会有大部分会变成1,可以用一些小技巧来保证复杂度不会太差,用一个tag变量去标记一下这个区间是不是全都相等,再用一个sam变量去标记区间全相等的时候的元素大小,这样修改的时候对于区间元素都相等的直接对sam进行gcd即可。最后用一个线段树维护标记。(虽然区间开方的题目我是用分块,不过线段树还是挺好写的

#include<bits/stdc++.h>
#define ls cur<<1
#define rs cur<<1|1 
using namespace std;

typedef long long ll;
const int maxn=2e5+10;

ll sum[maxn<<2],a[maxn<<2],ma[maxn<<2],gd[maxn<<2],tag[maxn<<2],sam[maxn<<2];


void pushup( int cur )
{
    sum[cur]=sum[ls]+sum[rs]; 
    tag[cur]=tag[ls] & tag[rs];
    if( tag[cur] ) 
    {
        if( sam[ls]==sam[rs] ) sam[cur]=sam[ls]; 
        else tag[cur]=0;
    }
}

void pushdown( int cur ,int l,int r )
{
    if( tag[cur] )
    {
        int mid=l+r>>1;
        sam[ls]=sam[rs]=sam[cur];
        sum[ls]=(mid-l+1)*sam[ls];
        sum[rs]=(r-mid)*sam[rs];
    }

}

void build( int cur,int l,int r )
{
    if( l==r )
    {
        sum[cur]=a[l];
        tag[cur]=1;
        sam[cur]=a[l];
        return;
    }
    tag[cur]=0;
    int mid=l+r>>1;
    build(ls,l,mid);
    build(rs,mid+1,r);
    pushup(cur);
}

void update( int cur,int l,int r,int L,int R,ll p )
{
    if( L<=l && r<=R )
    {
        if( tag[cur] )
        {
            sam[cur]=__gcd(sam[cur],p);
            sum[cur]=sam[cur]*(r-l+1);
            return;
        }
    }
    pushdown(cur,l,r);
    if( l==r )
    {
        sam[cur]=sum[cur]=__gcd(a[l],p);
        return;
    }
    int mid=l+r>>1;
    if( mid>=L ) update(ls,l,mid,L,R,p);
    if( mid<R )  update(rs,mid+1,r,L,R,p);
    pushup(cur);
}

ll get_sum( int cur,int l,int r,int L,int R )
{
    if( L<=l && r<=R ) return sum[cur];
    int mid=l+r>>1;
    ll ans=0;
    pushdown(cur,l,r);
    if( L<=mid ) ans+=get_sum(ls,l,mid,L,R);
    if( R>mid ) ans+=get_sum(rs,mid+1,r,L,R);
    return ans;
}


int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for( int i=1;i<=n;i++ ) scanf("%lld",&a[i]);

    build(1,1,n);
    while( m-- )
    {
        int opt,l,r,x;
        scanf("%d%d%d",&opt,&l,&r);
        if( opt==1 )
        {
            ll x;
            scanf("%lld",&x);
            update(1,1,n,l,r,x);
        }
        if( opt==2 ) 
        printf("%lld\n",get_sum(1,1,n,l,r) );
    }
}