线段树维护区间GCD(我永远爱GCD)
和区间内值为GCD的数的个数
因为区间越大,GCD只会越来越小,所以新的GCD如果不等于原来的GCD,那么这个子区间内就不会有数等于新GCD。
根据这个性质随便搞一下就行了。
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N=1000010;
int a[N],b[N];
struct Node{int gcd,cnt;Node(){gcd=cnt=0;}};
struct Segtree{
int gcd,l,r,cnt;
Segtree(){gcd=l=r=cnt=0;}
}t[N<<2];
int gcd(int a,int b){return b?gcd(b,a%b):a;}
void pushup(int cur) {
int d=gcd(t[cur<<1].gcd,t[cur<<1|1].gcd);
t[cur].gcd=d;t[cur].cnt=0;
if(d==t[cur<<1].gcd) t[cur].cnt+=t[cur<<1].cnt;
if(d==t[cur<<1|1].gcd) t[cur].cnt+=t[cur<<1|1].cnt;
}
void build(int l,int r,int cur) {
t[cur].l=l;t[cur].r=r;
if(l==r) {t[cur].gcd=a[l];t[cur].cnt=1;return;}
int mid=l+r>>1;
build(l,mid,cur<<1);
build(mid+1,r,cur<<1|1);
pushup(cur);
}
Node query(int l,int r,int cur) {
if(t[cur].l>=l&&t[cur].r<=r) {
Node x;x.gcd=t[cur].gcd;x.cnt=t[cur].cnt;
return x;
}
int mid=t[cur].l+t[cur].r>>1;
Node ans,tmp;
ans.gcd=-1;
if(l<=mid&&r>=t[cur].l) ans=query(l,r,cur<<1);
if(t[cur].r>=l&&r>mid){
tmp=query(l,r,cur<<1|1);
if(ans.gcd==-1) ans=tmp;
else {
int d=gcd(ans.gcd,tmp.gcd);
if(d!=ans.gcd) ans.cnt=0;
if(d==tmp.gcd) ans.cnt+=tmp.cnt;
ans.gcd=d;
}
}
return ans;
}
int n,q,l,r;
int main() {
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
build(1,n,1);
scanf("%d",&q);
while(q--) {
scanf("%d%d",&l,&r);
Node ans=query(l,r,1);
printf("%d
",r-l+1-ans.cnt);
}
return 0;
}