[题目链接] (https://nanti.jisuanke.com/t/41391)
题解:以每个位置建树,维护每个位置之后每个合法的位置加入线段树中。
#include<bits/stdc++.h>
#define mid (l+r)/2
using namespace std;
const int maxn = 1e5+10;
vector<int>G[maxn];
int a[maxn],l[maxn],r[maxn],ans[maxn];
int rt[maxn],sum[maxn*190],ls[maxn*190],rs[maxn*190];
int cnz ;
void up(int &o,int pre,int l,int r,int k)
{
o = ++cnz;
sum[o] = sum[pre] + 1;
ls[o] = ls[pre];
rs[o] = rs[pre];
if(l==r) return ;
if(k>mid) up(rs[o],rs[pre],mid+1,r,k);
else up(ls[o],ls[pre],l,mid,k);
}
int qu(int o,int l,int r,int ql,int qr)
{
if(ql<=l&&qr>=r) return sum[o];
int ans = 0;
if(ql<=mid) ans += qu(ls[o],l,mid,ql,qr);
if(qr>mid) ans += qu(rs[o],mid+1,r,ql,qr);
return ans ;
}
int main()
{
int n,m;scanf("%d%d",&n,&m);
int p;
for(int i=1;i<=n;i++)
{
scanf("%d",&p);
a[p] = i;
}
for(int i=1;i<n;i++)
{
for(int j=i*2;j<=n;j+=i)
if(a[j]>a[i])
G[a[i]].push_back(a[j]);
}
for(int i=1;i<n;i++){
for(int j=i*2;j<=n;j+=i)
if(a[i]>a[j])
G[a[j]].push_back(a[i]);
}
for(int i=1;i<=n;i++)
{
rt[i] = rt[i-1];
for(int j=0;j<G[i].size();j++)
up(rt[i],rt[i],1,n,G[i][j]);
}
for(int i=1;i<=m;i++)
{
scanf("%d%d",&l[i],&r[i]);
ans[i] = qu(rt[r[i]],1,n,l[i],r[i]) - qu(rt[l[i]-1],1,n,l[i],r[i]);
}
for(int i=1;i<=m;i++)
printf("%d\n",ans[i]);
}