链接:https://ac.nowcoder.com/acm/contest/949/H

这道题就是一道很基本的线段树的题目,但基本上把线段树的基础各种操作都放进去了。
我们知道,线段树维护和统计的东西要满足区间加法,而其中就包括了以下三个:

数字之和——总数字之和 = 左区间数字之和 + 右区间数字之和

最大公因数(GCD)——总GCD = gcd( 左区间GCD , 右区间GCD );

最大值——总最大值=max(左区间最大值,右区间最大值)

而这题全都包含了,所以可以当做一个比较好的板子。

以下是代码。

其中 __gcd 是c++库里的一个函数,跟手动gcd求最大公约数一样。

而求区间所有数的最大公约数的方法:

 

gcd(a,b)=gcd(a,ba
gcd(a,b,c)=gcd(a,ba,cb
gcd(a1,a2,,an)=gcd(a1,a2a1,a3a2,,anan1
 
所以在这里我们建树的时候存的是原数列的差分序列,从而来维护最大公约数。
C	小阳的贝壳  基本线段树+gcd性质_线段树C	小阳的贝壳  基本线段树+gcd性质_#include_02
  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 const int maxn=1e5+10;
  4 int a[maxn];
  5 struct node
  6 {
  7     int L,R;
  8     int mx,gcd;
  9     int sum;
 10 }tree[maxn<<2];
 11 void pushup(int u)
 12 {
 13     tree[u].mx=max(tree[u<<1].mx,tree[u<<1|1].mx);
 14     tree[u].gcd=__gcd(tree[u<<1].gcd,tree[u<<1|1].gcd);
 15     tree[u].sum=tree[u<<1].sum+tree[u<<1|1].sum;
 16 }
 17 void build(int l,int r,int root)
 18 {
 19     tree[root].L=l; tree[root].R=r;
 20     if(l==r){
 21         tree[root].sum=a[l];
 22         tree[root].mx=max(a[l],-a[l]);
 23         tree[root].gcd=max(a[l],-a[l]);
 24         return;
 25     }
 26     int mid=l+r>>1;
 27     build(l,mid,root<<1);
 28     build(mid+1,r,root<<1|1);
 29     pushup(root);
 30 }
 31 void update(int root,int pos,int val)
 32 {
 33     int L=tree[root].L;int R=tree[root].R;
 34     if(L==R){
 35         a[L]+=val;
 36         tree[root].sum=a[L];
 37         tree[root].mx=tree[root].gcd=max(a[L],-a[L]);
 38         return;
 39     }
 40     int mid=L+R>>1;
 41     if(pos<=mid) update(root<<1,pos,val);
 42     else update(root<<1|1,pos,val);
 43     pushup(root);
 44 }
 45 int query_max(int l,int r,int root)
 46 {
 47     int L=tree[root].L; int R=tree[root].R;
 48     if(l<=L&&r>=R){
 49         return tree[root].mx;
 50     }
 51     int mid=L+R>>1;
 52     int ans=0;
 53     if(l<=mid) ans=max(ans,query_max(l,r,root<<1));
 54     if(r>mid)  ans=max(ans,query_max(l,r,root<<1|1));
 55     return ans;
 56 }
 57 int query_sum(int l,int r,int root)
 58 {
 59     int L=tree[root].L; int R=tree[root].R;
 60     if(l<=L&&r>=R){
 61         return tree[root].sum;
 62     }
 63     int mid=L+R>>1;
 64     int ans=0;
 65     if(l<=mid) ans+=query_sum(l,r,root<<1);
 66     if(r>mid)  ans+=query_sum(l,r,root<<1|1);
 67     return ans;
 68 }
 69 int query_gcd(int l,int r,int root)
 70 {
 71     int L=tree[root].L; int R=tree[root].R;
 72     if(l<=L&&r>=R){
 73         return tree[root].gcd;
 74     }
 75     int mid=L+R>>1;
 76     int ans=0;
 77     if(l<=mid) ans=__gcd(ans,query_gcd(l,r,root<<1));
 78     if(r>mid)  ans=__gcd(ans,query_gcd(l,r,root<<1|1));
 79     return ans;
 80 }
 81 int main()
 82 {
 83     int n,m;
 84     scanf("%d%d",&n,&m);
 85     for(int i=1;i<=n;i++){
 86         scanf("%d",&a[i]);
 87     }
 88     for(int i=n;i>=1;i--){
 89         a[i]=a[i]-a[i-1];
 90     }
 91     build(1,n,1);
 92     while(m--){
 93         int op,l,r,x;
 94         scanf("%d%d%d",&op,&l,&r);
 95         if(op==1){
 96             scanf("%d",&x);
 97             update(1,l,x);
 98             if(r<=n-1) update(1,r+1,-x);
 99         }
100         else if(op==2){
101             if(l==r) printf("0\n");
102             else{
103                 int ans=query_max(l+1,r,1);
104                 printf("%d\n",ans);
105             }
106         }
107         else {
108             int tmp=query_sum(1,l,1);
109             if(r>l) tmp=__gcd(tmp,query_gcd(l+1,r,1));
110             printf("%d\n",tmp);
111         }
112     }
113 }
View Code