Codeforces Round #182 (Div. 1) Yaroslav and Divisors(离线+树状数组)

185 篇文章 0 订阅
10 篇文章 0 订阅

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<bits/stdc++.h>
#define N 200005
using namespace std;
typedef pair<int,int> pii;
vector<int> G[N];
vector<pii> 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<<ans[i]<<endl;
}



  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值