codeforces 301D Yaroslav and Divisors(树状数组)
Yaroslav has an array p = p1, p2, ..., pn (1 ≤ pi ≤ n), consisting of n distinct integers. Also, he has m queries:
- Query number i is represented as a pair of integers li, ri (1 ≤ li ≤ ri ≤ n).
- The answer to the query li, ri is the number of pairs of integers q, w (li ≤ q, w ≤ ri) such that pq is the divisor of pw.
Help Yaroslav, answer all his queries.
The first line contains the integers n and m (1 ≤ n, m ≤ 2·105). The second line contains n distinct integers p1, p2, ..., pn (1 ≤ pi ≤ n). The following m lines contain Yaroslav's queries. The i-th line contains integers li, ri (1 ≤ li ≤ ri ≤ n).
Print m integers — the answers to Yaroslav's queries in the order they appear in the input.
题目大意:给一个1~n的排列,有m个询问,问L到R之间有多少对数满足一个数是另一个数的约数。
思路:果然数学才是王道……
1~n个数,满足一个数是另一个数的约数的数对,一共有n/1 + n/2 + …… + n/n ≈ nlogn个(大概吧其实我也不会算),也就是32位够了
然后怎么计算L到R有多少对呢?本来想的是用1~R的对数减去1~L-1的对数,结果发现这样算的结果包含了一个属于1~L-1另一个属于L~R的合法对。
于是进一步思考,令x = 1~R的对数减去1~L-1的对数,y = 一个属于1~L-1另一个属于L~R的合法对数,答案ans = x - y。
这个好像没有办法在短时间内在线处理出来,于是采用离线处理。
i从1到n循环,对所有的query.L=i,减去sum[R] - sum[L-1],即上面所说的y(此时L~R的合法对还没被计算出来)。然后找出所有i的倍数,加到sum里面。再对所有的query.R=i,加上sum[R] - sum[L-1],即上面所说的x(此时L~R的合法对已经计算出来了)。
对于这种需要单点更新,区间求值的操作,树状数组可以满足你。
代码(498MS):
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; 6 7 const int MAXN = 200010; 8 9 int a[MAXN], pos[MAXN], tree[MAXN]; 10 int n, m; 11 12 int lowbit(int x) { 13 return x & (-x); 14 } 15 16 int get_sum(int k) { 17 int ans = 0; 18 while(k > 0) { 19 ans += tree[k]; 20 k -= lowbit(k); 21 } 22 return ans; 23 } 24 25 void modify(int k, int val) { 26 while(k <= n) { 27 tree[k] += val; 28 k += lowbit(k); 29 } 30 } 31 32 struct QUERY { 33 int id, L, R; 34 bool operator < (const QUERY &rhs) const { 35 return L < rhs.L; 36 } 37 } query[MAXN], query_t[MAXN]; 38 39 int ans[MAXN]; 40 41 int main() { 42 scanf("%d%d", &n, &m); 43 for(int i = 1; i <= n; ++i) { 44 scanf("%d", &a[i]); 45 pos[a[i]] = i; 46 } 47 for(int i = 1; i <= m; ++i) { 48 scanf("%d%d", &query[i].L, &query[i].R); 49 query_t[i].L = query[i].R; 50 query_t[i].R = query[i].L; 51 query[i].id = query_t[i].id = i; 52 } 53 sort(query + 1, query + m + 1); 54 sort(query_t + 1, query_t + m + 1); 55 for(int i = 1, j = 1, k = 1; i <= n; ++i) { 56 while(j <= m && query[j].L == i) { 57 ans[query[j].id] -= get_sum(query[j].R) - get_sum(query[j].L - 1); 58 ++j; 59 } 60 for(int p = a[i]; p <= n; p += a[i]) modify(pos[p], 1); 61 while(k <= m && query_t[k].L == i) { 62 ans[query_t[k].id] += get_sum(query_t[k].L) - get_sum(query_t[k].R - 1); 63 ++k; 64 } 65 } 66 for(int i = 1; i <= m; ++i) printf("%d\n", ans[i]); 67 }