NC220148. 简单的gcd
描述
你有一个长度为n 的数组A,你需要进行m 次操作,一共有如下三种类型的操作方式:
1:增加,将数组中一个数增加一个量;
2:减少,将数组中一个数减少一个量,当减少至0以下时保持为0;
3:询问,询问区间l,r之间数的总gcd(不一定是l到r,可能是r到l);输入描述
第一行输入两个整数n,m(n,m<=100000)
第二行输入n个整数ai。(ai<1000000)
接下来m行每行输入一个字符串,以及两个整数,字符串‘+’表示增加操作,字符串‘-’表示
减少操作,字符串‘Query’表示询问操作
输出描述
对于每个询问输出一行一个整数表示答案
示例1
输入:
5 6 6 9 10 8 4 + 4 1 + 4 4 + 1 3 + 1 4 - 1 1 Query 4 3
输出:
1
C++(clang++11) 解法, 执行用时: 182ms, 内存消耗: 4128K, 提交时间: 2021-03-29 10:57:08
#include<iostream> #include<algorithm> using namespace std; enum{maxn=400010}; int tree[maxn],arr[maxn]; int n; void build(int l=1,int r=n,int p=1){ if(l>r)return; if(l==r) { tree[p]=arr[l]; return ; } int mid=(l+r)/2; build(l,mid,2*p); build(mid+1,r,2*p+1); tree[p]=__gcd(tree[2*p],tree[2*p+1]); } void addpoint(int pos,int k,int l=1,int r=n,int p=1){ if(l>r)return ; if(l==r){ tree[p]+=k; tree[p]=max(tree[p],0); return ; } int mid=(l+r)/2; if(pos>mid)addpoint(pos,k,mid+1,r,2*p+1); else addpoint(pos,k,l,mid,2*p); tree[p]=__gcd(tree[2*p],tree[2*p+1]); } int find(int fl,int fr,int l=1,int r=n,int p=1){ if(l>r) return 0; if(fl<=l&&fr>=r) return tree[p]; int mid=(l+r)/2; int a=0,b=0; if(fl<=mid) a=find(fl,fr,l,mid,2*p); if(fr>mid) b=find(fl,fr,mid+1,r,2*p+1); return __gcd(a,b); } int m; char op[20]; int a,b; int main(){ //freopen("data.in","r",stdin); cin>>n>>m; for(int i=1;i<=n;++i) cin>>arr[i]; build(); for(int i=0;i<m;++i){ cin>>op>>a>>b; switch(op[0]){ case '+': addpoint(a,b);break; case '-':addpoint(a,-b);break; case 'Q': if(a>b) swap(a,b); cout<<find(a,b)<<endl; } } }