题目链接:http://codeforces.com/contest/474/problem/F
主要就是要求区间$gcd$以及这个区间内的数字等于区间$gcd$的有多少个。
没有修改用个线段树树直支持$gcd$查询,区间不断变大,$gcd$一定单调不增,所以如果左右子树的$gcd$在合并之后保持不变就合并子树的等于$gcd$的数字的数量,不然就可以清空为$0$了。
1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<vector> 5 #include<cstdlib> 6 #include<cmath> 7 #include<cstring> 8 using namespace std; 9 #define maxn 1001000 10 #define llg int 11 #define yyj(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout); 12 llg n,m,val[maxn],cs[maxn],T; 13 14 inline int getint() 15 { 16 int w=0,q=0; char c=getchar(); 17 while((c<'0' || c>'9') && c!='-') c=getchar(); if(c=='-') q=1,c=getchar(); 18 while (c>='0' && c<='9') w=w*10+c-'0', c=getchar(); return q ? -w : w; 19 } 20 21 struct node 22 { 23 llg val,cs; 24 void init() {val=cs=0;} 25 bool check() {if (val!=0 || cs!=0) return 0; return 1;} 26 }; 27 28 void build(llg o,llg l,llg r) 29 { 30 if (l==r) 31 { 32 val[o]=getint(); cs[o]=1; 33 return ; 34 } 35 llg lc=o<<1,rc=o<<1|1,mid=(l+r)>>1; 36 build(lc,l,mid),build(rc,mid+1,r); 37 //-----------------------Updata 38 val[o]=__gcd(val[lc],val[rc]); 39 if (val[o]==val[lc]) cs[o]+=cs[lc]; 40 if (val[o]==val[rc]) cs[o]+=cs[rc]; 41 } 42 43 node ask(llg o,llg l,llg r,llg L,llg R) 44 { 45 if (l>=L && r<=R) 46 { 47 node w; 48 w.cs=cs[o],w.val=val[o]; 49 return w; 50 } 51 node v1,v2; 52 v1.init(),v2.init(); 53 llg lc=o<<1,rc=o<<1|1,mid=(l+r)>>1; 54 if (L<=mid) v1=ask(lc,l,mid,L,R); 55 if (R>mid) v2=ask(rc,mid+1,r,L,R); 56 if (v1.check()) return v2; 57 if (v2.check()) return v1; 58 node vo; 59 vo.init(); 60 vo.val=__gcd(v1.val,v2.val); 61 if (vo.val==v1.val) vo.cs+=v1.cs; 62 if (vo.val==v2.val) vo.cs+=v2.cs; 63 return vo; 64 } 65 66 int main() 67 { 68 yyj("gcd"); 69 cin>>n; 70 build(1,1,n); 71 cin>>T; 72 while (T--) 73 { 74 llg l=getint(),r=getint(); 75 printf("%d ",r-l+1-ask(1,1,n,l,r).cs); 76 } 77 return 0; 78 }