版权声明:本文为DyingShu原创文章,转载请注明出处哦。 https://blog.csdn.net/DyingShu/article/details/82118110
又TM水了一道线段树…
题意:求区间GCD及等于这个GCD的数有多少个。输出区间长度-GCD数量
题解:
线段树维护区间GCD,再维护区间GCD数量。
显然当两个区间合并时,新区间的GCD等于左右区间GCD的GCD,而如果等于其中一个数,则数量就等于那个区间的GCD数量。
然后就完了。
#include<cstdio>
#include<algorithm>
using namespace std;
const int MAXN = 100001;
struct node{
int gcd, tag;
int l, r;
}t[MAXN << 2];
struct ANS{
int tag, gcd;
}ans;
int a[MAXN];
inline int read(){
int k = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') f = -1; ch = getchar();}
while(ch >= '0' && ch <= '9'){k = k*10 + ch - '0'; ch = getchar();}
return k * f;
}
int GCD(int a, int b){return b ? GCD(b, a % b) : a;}
inline void pushup(int u){
t[u].gcd = GCD(t[u << 1].gcd, t[u << 1 | 1].gcd);
if(t[u << 1].gcd == t[u << 1 | 1].gcd) t[u].tag = t[u << 1].tag + t[u << 1 | 1].tag;
else if(t[u].gcd == t[u << 1].gcd) t[u].tag = t[u << 1].tag;
else if(t[u].gcd == t[u << 1 | 1].gcd) t[u].tag = t[u << 1 | 1].tag;
else t[u].tag = 0;
}
void build(int u, int L, int R){
t[u].l = L, t[u].r = R;
if(L == R){t[u].gcd = read(), t[u].tag = 1;return;}
int mid = (L + R) >> 1;
build(u << 1, L, mid), build(u << 1 | 1, mid + 1, R);
pushup(u);
}
ANS query(int u, int L, int R){
// printf("u = %d\n", u);
ANS tmp;
if(t[u].l >= L && t[u].r <= R){
tmp.gcd = t[u].gcd;
tmp.tag = t[u].tag;
return tmp;
}
if(t[u << 1].r >= R) return query(u << 1, L, R);
if(t[u << 1 | 1].l <= L) return query(u << 1 | 1, L, R);
ANS s1 = query(u << 1, L, R), s2 = query(u << 1 | 1, L, R);
tmp.gcd = GCD(s1.gcd, s2.gcd);
if(s1.gcd == s2.gcd) tmp.tag = s1.tag + s2.tag;
else if(tmp.gcd == s1.gcd) tmp.tag = s1.tag;
else if(tmp.gcd == s2.gcd) tmp.tag = s2.tag;
else tmp.tag = 0;
return tmp;
}
int main(){
// freopen("in.txt", "r", stdin);
int n = read();
build(1, 1, n);
int m = read();
while(m--){
int l = read(), r = read();
ans = query(1, l, r);
printf("%d\n", r - l + 1 - ans.tag);
}
return 0;
}