题目链接:点击打开链接
//cf 301d
//题目大意:一段序列(只包含1—n),一个数如果是另一个数(包括本身)的因子则成为一对,求某个区间内的对数
//大概思路:
//
// 记录每个数的位置;
// 离线操作;
// i从左往右扫一遍,判断a[i]*j(1<= j<= n/a[i])的位置p,
// 如果p<= i,则在i位置上加一
// 如果p> i,则在p位置上记录i,当再次扫到p时在i位置上加一
// 这样就避免了重复统计的问题(可以在纸上画一画),用树状数组统计求和
#include <iostream>
#include <algorithm>
#include <fstream>
#include <sstream>
#include <iomanip>
#include <cstdio>
#include <vector>
#include <cstring>
#include <cmath>
#include <queue>
#include <stack>
#include <set>
#include <map>
#define N 200020
using namespace std;
int a[N], b[N], c[N], r[N], l[N], ans[N], n, m;
vector<int> ask[N];
vector<int> d[N];
void add(int x)
{
while(x<= n)
{
c[x]++;
x+= x&-x;
}
}
int sum(int x)
{
int s= 0;
while(x)
{
s+= c[x];
x-= x&-x;
}
return s;
}
int main()
{
while(scanf("%d%d", &n, &m)== 2)
{
for(int i= 1; i<= n; i++)
{
scanf("%d", &a[i]);
b[a[i]]= i;
}
for(int i= 1; i<= m; i++)
{
scanf("%d%d", &l[i], &r[i]);
ask[r[i]].push_back(i);
}
for(int i= 1; i<= n; i++)
{
for(int j= 0; j< (int)d[i].size(); j++) add(d[i][j]);
for(int j= 1; j* a[i]<= n; j++)
{
int p= b[j* a[i]];
if(p<= i) add(p);
else d[p].push_back(i);
}
for(int j= 0; j< (int)ask[i].size(); j++)
{
int p= ask[i][j];
ans[p]= sum(r[p])- sum(l[p]- 1);
}
}
for(int i= 1; i<= m; i++) printf("%d\n", ans[i]);
}
return 0;
}