Codeforces Round #182 (Div. 1) 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.

Please, do not use the %lld specifier to read or write 64-bit integers in C++. It is preferred to use the cincout streams or the %I64dspecifier.

Examples
input
1 1
1
1 1
output
1
input
10 9
1 2 3 4 5 6 7 8 9 10
1 10
2 9
3 8
4 7
5 6
2 2
9 10
5 10
4 10
output
27
14
8
4
2
1
2
7
9


分析:注意非常重要的一点就是整个数列是一个排列,这样对于一个1到n的排列成倍数关系的数其实是非常少的,大概是nlogn这个数量级,所以我们先把所有成倍关系的两元组求出来,这样设其中下标较大的下标为x,较小的为y,那么问题就转化为了每次求一段区间l到r中包含的成对的[x,y]的个数,这个问题有一个经典的离线做法,从左向右扫描序列,每次把小于当前位置i的y对应的x更新到树状数组里边,那么对于r = i的询问,其答案就是sum(r) - sum(l-1).
#include
#define N 200005
using namespace std;
typedef pair pii;
vector G[N];
vector ask[N];
int n,m,x,p[N],f[N],ans[N];
void Insert(int x)
{
    int p = x;
    while(p <= n)
    {
        f[p]++;
        p += p & (-p);
    }
}
int Sum(int x)
{
    int p = x,ans = 0;
    while(p)
    {
        ans += f[p];
        p -= p & (-p);
    }
    return ans;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i = 1;i <= n;i++)
    {
        scanf("%d",&x);
        p[x] = i;
    }
    for(int i = 1;i <= n;i++)
     for(int j = i;j <= n;j+=i)
     {
        int x = p[i],y = p[j];
        if(x > y) swap(x,y);
        G[y].push_back(x);
     }
    for(int i = 1;i <= m;i++)
    {
        int l,r;
        scanf("%d%d",&l,&r);
        ask[r].push_back(make_pair(l,i));
    }
    for(int i = 1;i <= n;i++)
    {
        for(int v : G[i]) Insert(v);
        for(pii v : ask[i]) ans[v.second] = Sum(i) - Sum(v.first-1);
    }
    for(int i = 1;i <= m;i++) cout<



你可能感兴趣的:(ACM,好题,离线算法)