CodeForces 272F - Ant colony线段树
题意:给出长度为n的串a,然后 给出q个询问 。对于每个询问 l,r,有一个计算其中对应的数的能量值的方法,比如power[l] 的计算方法就是 在区间[l,r]中能被 a[l]整除的数的个数。问这个区间中除去能量值等于r-l的个数还剩多少个。
因为个数 等于r-l ,就相当于最小的数是 这个区间的最大公约数。就是求如果存在最小的数等于这个区间的最大公约数,最小的数的个数。
#include <cstdio> #include <cstring> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <cstdlib> #include <list> #include <set> #include <queue> #include <stack> #include <math.h> using namespace std; typedef long long LL; #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 const int maxn = 111111; const int INF = 1000000000 + 2; int sum[maxn << 2], Min[maxn << 2], ret[maxn << 2]; int a[maxn]; int gcd(int a, int b) { if (a%b == 0) return b; return gcd(b, a%b); } void up(int rt) { Min[rt] = min(Min[rt << 1], Min[rt << 1 | 1]); sum[rt] = gcd(sum[rt << 1], sum[rt << 1 | 1]); if (Min[rt << 1] == Min[rt << 1 | 1]) ret[rt] = ret[rt << 1] + ret[rt << 1 | 1]; if (Min[rt << 1] > Min[rt << 1 | 1]) ret[rt] = ret[rt << 1 | 1]; if (Min[rt << 1] < Min[rt << 1 | 1]) ret[rt] = ret[rt << 1]; } void build(int l, int r, int rt) { if (l == r){ Min[rt] = sum[rt] = a[l]; ret[rt] = 1; return; } int mid = (l + r) >> 1; build(lson); build(rson); up(rt); } int askmin(int L, int R, int l, int r, int rt) { int ans = INF; if (L <= l&&r <= R) return Min[rt]; int mid = (l + r) >> 1; if (L <= mid) ans = askmin(L, R, lson); if (R > mid) ans = min(ans, askmin(L, R, rson)); return ans; } int askgcd(int L, int R, int l, int r, int rt) { if (L <= l&&r <= R) return sum[rt]; int ans1 = -1; int ans2 = -1; int mid = (l + r) >> 1; if (L <= mid) ans1 = askgcd(L, R, lson); if (R>mid) ans2 = askgcd(L, R, rson); if (ans1 == -1) return ans2; if (ans2 == -1) return ans1; return gcd(ans1, ans2); } int askret(int L, int R, int m, int l, int r, int rt) { int ans = 0; if (L <= l&&r <= R){ if (m == Min[rt]) return ret[rt]; return 0; } int mid = (l + r) >> 1; if (L <= mid) ans += askret(L, R, m, lson); if (R>mid) ans += askret(L, R, m, rson); return ans; } int main() { int n, l, r, q; cin >> n; for (int i = 1; i <= n; i++) scanf("%d", &a[i]); build(1, n, 1); cin >> q; for (int i = 0; i < q; i++){ scanf("%d%d", &l, &r); int m = askmin(l, r, 1, n, 1); int Gcd = askgcd(l, r, 1, n, 1); if (Gcd == m)printf("%d\n", r - l + 1 - askret(l, r, m, 1, n, 1)); else printf("%d\n", r - l + 1); } return 0; }