题目
大意:两个操作 一个操作是区间加上d 另一个是求区间的GCD
思路:首先如果区间修改使用lazytag的话 难以维护GCD 可以用数学性质gcd(x,y,z)=gcd(x,y-x,z-y)
使用差分 来将区间修改改为两个单点修改 只需要将b[l]+=d b[r+1]-=d 再维护一下gcd即可
query是为了求得区间gcd queryy是为了将差分数组复原为原值 即第一个数x 再做gcd
记得要用ll
还有一个坑点:小心越界
if(y+1<=n) change(1,y+1,-z);
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define endl '\n'
struct tree{
ll l,r,val,sum;
}t[500050<<2];
ll n,m;
ll a[500050],b[500050];
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
void build(ll k,ll l,ll r)
{
if(l==r) t[k]={l,r,b[l],b[l]};
else{
t[k]={l,r};
ll mid=l+r>>1;
build(k<<1,l,mid); build(k<<1|1,mid+1,r);
t[k].val=gcd(t[k<<1].val,t[k<<1|1].val);
t[k].sum=t[k<<1].sum+t[k<<1|1].sum;
}
}
void change(ll k,ll x,ll d)
{
if(t[k].l==t[k].r&&t[k].l==x){
t[k].val+=d; t[k].sum+=d;
return;
}
ll mid=t[k].l+t[k].r>>1;
if(x<=mid) change(k<<1,x,d);
else change(k<<1|1,x,d);
t[k].val=gcd(t[k<<1].val,t[k<<1|1].val);
t[k].sum=t[k<<1].sum+t[k<<1|1].sum;
}
ll query(ll k,ll l,ll r)
{
if(t[k].l>=l&&t[k].r<=r){
return t[k].val;
}
ll ans=0;
ll mid=t[k].l+t[k].r>>1;
if(l<=mid) ans=gcd(ans,query(k<<1,l,r));
if(mid<r) ans=gcd(ans,query(k<<1|1,l,r));
return ans;
}
ll queryy(ll k,ll l,ll r)
{
if(t[k].l>=l&&t[k].r<=r){
return t[k].sum;
}
ll ans=0;
ll mid=t[k].l+t[k].r>>1;
if(l<=mid) ans+=queryy(k<<1,l,r);
if(mid<r) ans+=queryy(k<<1|1,l,r);
return ans;
}
int main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<=n;i++){
b[i]=a[i]-a[i-1];
}
build(1,1,n);
for(int i=1;i<=m;i++){
char ch; cin>>ch;
if(ch=='Q'){
ll x,y; cin>>x>>y;
ll tmp=queryy(1,1,x);
cout<<llabs(gcd(tmp,query(1,x+1,y)))<<endl;
}
else{
ll x,y,z; cin>>x>>y>>z;
change(1,x,z);
if(y+1<=n) change(1,y+1,-z);
}
}
return 0;
}