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 liri (1 ≤ li ≤ ri ≤ n).
  • The answer to the query li, ri is the number of pairs of integers qw (li ≤ q, w ≤ ri) such that pq is the divisor of pw.

 

Help Yaroslav, answer all his queries.

Input

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).

Output

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 }
View Code

 

posted @ 2013-08-14 12:26  Oyking  阅读(897)  评论(0编辑  收藏  举报