题意:维护支持以下两种操作的序列:1 l r询问a[l...r]的gcd,2 l r x把a[l...r]全部+x
题解:一道经典题。根据gcd(a,b)=gcd(a-b,b)以及区间加可知,这题可以差分求解。然后只需要维护支持单点加减和区间查询gcd、差分和的线段树即可,复杂度O(nlog2n),因为要求区间gcd。
#include<bits/stdc++.h> #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 using namespace std; const int N=1e5+7; int n,m,a[N],d[N<<2],s[N<<2]; void pushup(int rt){d[rt]=__gcd(d[rt<<1],d[rt<<1|1]),s[rt]=s[rt<<1]+s[rt<<1|1];} void build(int l,int r,int rt) { if(l==r){d[rt]=s[rt]=a[l];return;} int mid=l+r>>1; build(lson),build(rson); pushup(rt); } void update(int k,int v,int l,int r,int rt) { if(l==r){a[l]+=v,d[rt]=s[rt]=a[l];return;} int mid=l+r>>1; if(k<=mid)update(k,v,lson);else update(k,v,rson); pushup(rt); } int query_d(int L,int R,int l,int r,int rt) { if(L>R)return 0; if(L<=l&&r<=R)return d[rt]; int mid=l+r>>1,ret=0; if(L<=mid)ret=__gcd(ret,query_d(L,R,lson)); if(R>mid)ret=__gcd(ret,query_d(L,R,rson)); return ret; } int query_s(int L,int R,int l,int r,int rt) { if(L<=l&&r<=R)return s[rt]; int mid=l+r>>1,ret=0; if(L<=mid)ret+=query_s(L,R,lson); if(R>mid)ret+=query_s(L,R,rson); return ret; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)scanf("%d",&a[i]); for(int i=n;i;i--)a[i]-=a[i-1]; build(1,n,1); while(m--) { int op,l,r,x;scanf("%d%d%d",&op,&l,&r); if(op==1)printf("%d\n",abs(__gcd(query_d(l+1,r,1,n,1),query_s(1,l,1,n,1)))); else{ scanf("%d",&x); update(l,x,1,n,1); if(r<n)update(r+1,-x,1,n,1); } } }