看区间是所有数字因子的数的个数,其实就是看区间等于区间gcd的数的个数。
我们直接线段树区间维护这个个数即可。
或者维护区间gcd,然后主席树计算区间等于gcd的个数。
AC代码:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include
//#define int long long
using namespace std;
const int N=1e5+10;
int n,a[N],q;
struct node{int cnt,gd;}t[N<<2],c;
inline node merge(node a,node b){
c.gd=__gcd(a.gd,b.gd);
c.cnt=(a.gd==c.gd)*a.cnt+(b.gd==c.gd)*b.cnt;
return c;
}
#define mid (l+r>>1)
void build(int p,int l,int r){
if(l==r){t[p].gd=a[l],t[p].cnt=1; return ;}
build(p<<1,l,mid),build(p<<1|1,mid+1,r);
t[p]=merge(t[p<<1],t[p<<1|1]);
}
node ask(int p,int l,int r,int ql,int qr){
if(l==ql&&r==qr) return t[p];
if(qr<=mid) return ask(p<<1,l,mid,ql,qr);
else if(ql>mid) return ask(p<<1|1,mid+1,r,ql,qr);
else return merge(ask(p<<1,l,mid,ql,mid),ask(p<<1|1,mid+1,r,mid+1,qr));
}
signed main(){
cin>>n;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
cin>>q; build(1,1,n);
for(int i=1,l,r;i<=q;i++)
scanf("%d %d",&l,&r),printf("%d\n",r-l+1-ask(1,1,n,l,r).cnt);
return 0;
}