牛客 小阳的贝壳 ###K ###K //K
题目链接:https://ac.nowcoder.com/acm/contest/5803/C
思路:根据前两个操作 很容易想到要用线段树来维护一个差分数组
用一个mx 来维护差分区间的最大值即可
要注意的是 最大值的时候取绝对值的时机不要出错 还有差分建树要1到n+1
剩下关键就是如何要维护区间的gcd了 这里需要知道一个gcd的性质
gcd(a,b)=gcd(a,b-a) gcd(a,b,c)=gcd(a,b-a,c-b)
可以根据辗转相除法 gcd(a,b)=gcd(b,a%b) 那么就能得gcd(a,b)=gcd(b,a-b)
因为根据取模的含义 a%b=a-k*b 两者在同一个同余系中所以两者gcd一样
因为是有负数之间的gcd 所以要加abs 知道要求的是gcd(a,b-a,c-b)那么就还需要一个sum
维护一个前缀和来得到a (因为差分的前缀和就是原来的数)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 #define pb push_back 5 const int maxn =1e5+10; 6 const int mod=1e9+7; 7 ll GCD(ll a,ll b) 8 { 9 if(b==0) return a; 10 else return GCD(b,a%b); 11 } 12 int a[maxn]; 13 int n,m; 14 struct ac 15 { 16 int l,r; 17 ll gcd,mx; 18 ll sum; 19 }; 20 ac tree[maxn<<2]; 21 void pushup(int x) 22 { 23 tree[x].mx=max(abs(tree[x<<1].mx),abs(tree[x<<1|1].mx)); 24 tree[x].gcd=GCD(tree[x<<1].gcd,tree[x<<1|1].gcd); 25 tree[x].sum=tree[x<<1].sum+tree[x<<1|1].sum; 26 } 27 void build(int x,int l,int r) 28 { 29 tree[x].l=l,tree[x].r=r; 30 if(l==r) 31 { 32 tree[x].gcd=a[l]; 33 tree[x].mx=a[l]; 34 tree[x].sum=a[l]; 35 } 36 else 37 { 38 int mid=(l+r)/2; 39 build(x<<1,l,mid); 40 build(x<<1|1,mid+1,r); 41 pushup(x); 42 } 43 44 } 45 void update(int x,int pos,int v) 46 { 47 int L=tree[x].l,R=tree[x].r; 48 if(L==R) 49 { 50 tree[x].gcd+=v; 51 tree[x].sum+=v; 52 tree[x].mx+=v; 53 } 54 else 55 { 56 int mid=(L+R)/2; 57 if(pos<=mid) update(x<<1,pos,v); 58 if(pos>mid) update(x<<1|1,pos,v); 59 pushup(x); 60 } 61 } 62 ll querymax(int x,int l,int r) 63 { 64 int L=tree[x].l,R=tree[x].r; 65 if(l<=L&&R<=r) 66 { 67 return tree[x].mx; 68 } 69 else 70 { 71 int mid=(L+R)/2; 72 ll ans=-1; 73 if(l<=mid) ans=max(ans,abs(querymax(x<<1,l,r))); 74 if(r>mid) ans=max(ans,abs(querymax(x<<1|1,l,r))); 75 return ans; 76 } 77 } 78 ll querygcd(int x,int l,int r) 79 { 80 int L=tree[x].l,R=tree[x].r; 81 if(l<=L&&R<=r) 82 { 83 return tree[x].gcd; 84 } 85 else 86 { 87 int mid=(L+R)/2; 88 ll ans=0; 89 if(l<=mid) ans=GCD(ans,querygcd(x<<1,l,r)); 90 if(mid<r) ans=GCD(ans,querygcd(x<<1|1,l,r)); 91 return ans; 92 } 93 } 94 ll querysum(int x,int l,int r) 95 { 96 int L=tree[x].l,R=tree[x].r; 97 if(l<=L&&R<=r) 98 { 99 return tree[x].sum; 100 } 101 else 102 { 103 int mid=(L+R)/2; 104 ll ans=0; 105 if(l<=mid) ans+=querysum(x<<1,l,r); 106 if(r>mid) ans+=querysum(x<<1|1,l,r); 107 return ans; 108 } 109 } 110 int main() 111 { 112 ios::sync_with_stdio(false); 113 cin.tie(0); 114 cin>>n>>m; 115 for(int i=1;i<=n;i++) 116 { 117 cin>>a[i]; 118 } 119 for(int i=n;i>=1;i--) 120 { 121 a[i]=a[i]-a[i-1]; 122 } 123 build(1,1,n+1); //因为差分的原因要多后一位 124 while(m--) // 不然可能会越界 125 { 126 int d,l,r,x; 127 cin>>d>>l>>r; 128 if(d==1) 129 { 130 cin>>x; 131 update(1,l,x); 132 /*if(r==n) 如果建树不用n+1 就要补上这句 133 continue;*/ 134 update(1,r+1,-x); 135 } 136 else if(d==2) 137 { 138 if(l==r) 139 cout<<0<<'\n'; 140 else 141 cout<<querymax(1,l+1,r)<<'\n'; 142 } 143 else 144 { 145 if(l==r) 146 { 147 cout<<querysum(1,1,l)<<'\n'; 148 } 149 else 150 { 151 ll ans1=querygcd(1,l+1,r); 152 ll ans2=querysum(1,1,l); 153 cout<<abs(GCD(ans1,ans2))<<'\n'; 154 } 155 } 156 } 157 158 159 160 }

浙公网安备 33010602011771号