描述
给定一个长度为N的数列A,以及M条指令 (N≤5*10^5, M<=10^5),每条指令可能是以下两种之一:
“C l r d”,表示把 A[l],A[l+1],…,A[r] 都加上 d。
“Q l r”,表示询问 A[l],A[l+1],…,A[r] 的最大公约数(GCD)。
输入格式
第一行两个整数N,M,第二行N个整数Ai,接下来M行每条指令的格式如题目描述所示。
输出格式
对于每个询问,输出一个整数表示答案。
样例输入
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
数据范围与约定
- N,M≤2*10^5,l<=r,数据保证任何时刻序列中的数都是不超过2^62-1的正整数。
根据九章算术,gcd(x,y)=gcd(x,y-x),可以进一部扩展gcd(x,y,z)=gcd(x,y-x,z-y),同时n项也成立,
gcd(a[i],a[i+1],a[i+2]...a[n])=gcd(a[i],a[i+1]-a[i],a[i+2]-a[i+1]...a[n]-a[n-1]那么就可以用线段树维护b[i]=a[i]-a[i-1]每次c l r d
只有a[l]-a[l-1]加d,即b[i]+d;只有a[r+1]-a[r]减d其他的项都不变,故只更新b[l],b[r+1]即可,
a数组可以用 区间更新,单点查询 树状数组维护
Q l r 输出 gcd(a[l]+sum(l),query(1,l+1,r))就行了
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<stack>
#include<cstdlib>
#include<cctype>
using namespace std;
typedef long long ll;
typedef pair<int,int>P;
const int len=5e5+5;
struct Node{
int l,r;
ll v;//gcd
int mid()
{return (l+r)/2;}
}node[len<<2];
int n,m;
ll arr[len];//用来存初始输入的a数组
ll bet[len];//用来存a[i]-a[i-1]
ll c[len];
ll gcd(ll a,ll b)
{
return b==0?a:gcd(b,a%b);
}
void pushup(int i)
{
node[i].v=gcd(node[i*2].v,node[i*2+1].v);
}
void built(int i,int l,int r)
{
node[i].l=l;node[i].r=r;
if(l==r)
{
node[i].v=bet[l];
return ;
}
int mid=node[i].mid();
built(i*2,l,mid);
built(i*2+1,mid+1,r);
pushup(i);
}
ll query(int i,int l,int r)
{
if(l<=node[i].l&&node[i].r<=r)return llabs(node[i].v);
int mid=node[i].mid();
ll v=0;
if(l<=mid)v=gcd(v,query(i*2,l,r));//0与x的gcd为x
if(r>mid)v=gcd(v,query(i*2+1,l,r));
return llabs(v);//a[i]-a[i-1]可能为负数
}
void update(int i,int x,ll v)
{
if(node[i].l==node[i].r)
{
node[i].v+=v;
return ;
}
int mid=node[i].mid();
if(x<=mid)update(i*2,x,v);
else update(i*2+1,x,v);
pushup(i);
}
void add(int i,ll v)
{
for(;i<=n;i+=i&-i)c[i]+=v;
}
ll sum(int i)
{
ll ans=0;
for(;i;i-=i&-i)ans+=c[i];
return ans;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)scanf("%lld",arr+i),bet[i]=arr[i]-arr[i-1];
built(1,1,n);//建立维护b[i]=a[i]-[i-1]的线段树
while(m--)
{
char str[3];int l,r;ll v;
scanf("%s",str);
if(str[0]=='Q')
{
scanf("%d%d",&l,&r);
ll x=arr[l]+sum(l);
ll y=query(1,l+1,r);
printf("%lld\n",gcd(x,y));
}
else
{
scanf("%d%d%lld",&l,&r,&v);
add(l,v);add(r+1,-v);
update(1,l,v);update(1,r+1,-v);
}
}
}