题目
题解思路
利用更相减损术(如图所示),我们可以让线段树存入原数组差分数组,这样区间的加法就变成了单点的加法,而且两边的gcd只需对一个位置的sum gcd一下,其他的都是可以传递的 。
这样的话,这题的其他操作就有点类似245. 你能回答这些问题吗了
AC代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#include <algorithm>
#include <map>
#include <string>
using namespace std;
const int INF = 0x3f3f3f3f;
struct node
{
long long sum , d;
int l,r;
};
const int N = 500100 ;
long long a[N];
node tee[4*N];
int n , m ;
void pushup (node &u , node&l , node&r )
{
u.sum = l.sum + r.sum ;
u.d = __gcd(l.d , r.d ) ;
}
void pushup(int i )
{
pushup( tee[i] , tee[i*2] , tee[i*2+1] );
}
void in(int i , int t1 , int t2)
{
tee[i].l = t1 , tee[i].r = t2;
if ( t1 == t2 )
{
tee[i].sum = a[t1] - a[t1-1] ;
tee[i].d = tee[i].sum ;
return ;
}
int j = (t1+t2)/2;
in(i*2,t1,j);
in(i*2+1,j+1,t2);
pushup(i);
}
node sea( int i ,int t1 , int t2 )
{
if ( tee[i].l >= t1 && tee[i].r <= t2 )
return tee[i];
// pd(i);
int mid = tee[i].l + tee[i].r >> 1 ;
if ( t2 <= mid )
return sea(i*2 , t1 ,t2 );
else if ( t1 > mid )
return sea(i*2+1 , t1 , t2 );
else
{
node le = sea(i*2 , t1 , t2 );
node ri = sea(i*2+1 , t1 , t2 );
node res ;
pushup(res,le,ri);
return res ;
}
}
void _add( int i , int t1 , int t2 , long long vv )
{
if ( tee[i].l >= t1 && tee[i].r <= t2 )
{
tee[i].sum += vv ;
tee[i].d += vv ;
return;
}
if ( tee[i*2].r >= t1)
_add(i*2,t1,t2,vv);
if (tee[i*2+1].l <= t2)
_add(i*2+1,t1,t2,vv);
pushup(i);
}
int main ()
{
ios::sync_with_stdio(false);
cin >> n >> m ;
for (int i = 1 ; i <= n ; i++ )
cin >> a[i] ;
in(1 , 1 , n );
while ( m-- )
{
char ch[2] ;
int t1,t2;
long long t3 ;
cin >> ch ;
if ( ch[0] == 'Q' )
{
cin >> t1 >> t2 ;
node le = sea(1,1,t1);
node ri = {0,0,0,0};
if ( t1 + 1 <= t2 )
ri = sea(1,t1 + 1 , t2 );
cout<<abs(__gcd(le.sum , ri.d ))<<"\n";
}else
{
cin >> t1 >> t2 >> t3 ;
_add(1 , t1 , t1 , t3);
if ( t2 + 1 <= n )
_add(1, t2+1 , t2 + 1 , -t3 );
}
}
return 0 ;
}