题目链接:https://nanti.jisuanke.com/t/41391
题解:先找出每一对(pi,pj),那么i, j 记录为 区间[l, r],则查询就变为,在[L,R]内有多少区间,然后我们离线+线段树就可以搞定了,按照 r 排序,对应进行区间查询即可
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int pos[N];
int a[N];
int n, m;
vector<int> v[N];
struct node {
int l, r;
int val;
}tree[N << 2];
struct QUE {
int l, r;
int id;
}q[N];
int ans[N];
bool cmp1(QUE x, QUE y) {
return x.r < y.r;
}
void build(int l, int r, int cur) {
tree[cur].l = l;
tree[cur].r = r;
tree[cur].val = 0;
if(l == r) return;
int mid = (l + r) >> 1;
build(l, mid, cur << 1);
build(mid + 1, r, cur << 1 |1);
}
void update(int pos, int cur) {
if(tree[cur].l == tree[cur].r) {
tree[cur].val++;
return;
}
if(pos <= tree[cur << 1].r) update(pos, cur <<1);
else update(pos, cur << 1 |1);
tree[cur].val = tree[cur << 1].val + tree[cur << 1 | 1].val;
}
int query(int pl, int pr, int cur) {
if(pl <= tree[cur].l && tree[cur].r <= pr) {
return tree[cur].val;
}
int res = 0;
if(pl <= tree[cur << 1].r) res += query(pl, pr, cur << 1);
if(pr >= tree[cur << 1 | 1].l) res += query(pl, pr, cur << 1 | 1);
return res;
}
int main() {
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
pos[a[i]] = i;
}
int l, r;
for(int i = 1; i <= n; i++) {
for(int j = a[i] + a[i]; j <= n; j += a[i]) {
l = i;
r = pos[j];
if(l > r) swap(l, r);
v[r].push_back(l);
}
}
for(int i = 1; i <= m; i++)
scanf("%d %d", &q[i].l, &q[i].r), q[i].id = i;
sort(q + 1, q+ 1 + m, cmp1);
build(1, n, 1);
for(int j = 1, i = 1; i <= n; i++) {
for(int k = 0; k < v[i].size(); k++)
update(v[i][k], 1);
while(j <= m && q[j].r == i) {
ans[q[j].id] = query(q[j].l, q[j].r, 1);
j++;
}
}
for(int i = 1; i <= m; i++)
printf("%d\n", ans[i]);
return 0;
}