题目大意
给定一个序列,支持查询区间中等于gcd的数字有多少个,输出\(len - num\)。
\(n \leq 10^5\)
思路
一个区间等于gcd的数字个数取决于两个子区间的数字个数。判断即可
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int a[N];
int n,m;
struct node
{
int l,r;
int sum;
int gcd;
}t[N << 2];
int gcd(int a,int b) {
return b == 0 ? a : gcd(b,a % b);
}
void update(int rt) {
int ch = rt << 1;
t[rt].gcd = gcd(t[ch].gcd,t[ch + 1].gcd);
if(t[ch].gcd == t[ch + 1].gcd) t[rt].sum = t[ch].sum + t[ch + 1].sum;
else if(t[rt].gcd == t[ch].gcd) t[rt].sum = t[ch].sum;
else if(t[rt].gcd == t[ch + 1].gcd) t[rt].sum = t[ch + 1].sum;
else t[rt].sum = 0;
}
void build(int l,int r,int rt) {
t[rt].l = l;
t[rt].r = r;
if(l == r) {
t[rt].gcd = a[l];
t[rt].sum = 1;
return;
}
int ch = rt << 1;
int mid = (l + r) >> 1;
build(l,mid,ch);
build(mid + 1,r,ch + 1);
update(rt);
}
node query(int l,int r,int rt) {
if(l == t[rt].l and r == t[rt].r) {
return t[rt];
}
int mid = (t[rt].l + t[rt].r) >> 1;
int ch = rt << 1;
if(r <= mid) {
return query(l,r,ch);
}
else if(l > mid) {
return query(l,r,ch + 1);
}else {
node tmp1 = query(l,mid,ch);
node tmp2 = query(mid + 1,r,ch + 1);
node res;
res.l = l;
res.r = r;
res.gcd = gcd(tmp1.gcd,tmp2.gcd);
if(tmp1.gcd == tmp2.gcd) res.sum = tmp1.sum + tmp2.sum;
else if(res.gcd == tmp1.gcd) res.sum = tmp1.sum;
else if(res.gcd == tmp2.gcd) res.sum = tmp2.sum;
else res.sum = 0;
return res;
}
}
int main () {
scanf("%d",&n);
for(int i = 1;i <= n; i ++) {
scanf("%d",&a[i]);
}
build(1,n,1);
cin >> m;
while(m --) {
int l,r;
scanf("%d %d",&l,&r);
printf("%d\n",r - l + 1 - query(l,r,1).sum);
}
return 0;
}