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

 

你可能感兴趣的:(codeforces)