题目链接
题意:给定初始数组,m个询问,每次询问问你【l,r】内一个数是另一个数的因子,求数量。
思路:我们一开始是想按右端点排序,然后计算以下query(s【i】.r)-query(s【i】.l-1)就行了,但是这样有一个问题,我们忘了减去【1,l-1】里的每个的每个数对【l,r】里的数产生的贡献了,但是这个贡献不好直接减,于是有一个神乎奇迹的解法,就是再这一个数组,s1维护的是左端点,s2维护的是右端点,当i作为左端点的时候减去【1,l-1】里的每个的每个数对【l,r】里的数产生的贡献,当i作为右端点时就是用我们一开始的做法直接算就好了,因为这个时候该减的都已经减了。
#include<bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
typedef long long ll;
#define lowbit(i) (i)&(-i)
int a[maxn],pos[maxn];
ll c[maxn],ans[maxn];
struct node{
int l,r,id;
}s1[maxn],s2[maxn];
bool cmp1(const node &a,const node &b)
{
return a.l==b.l?a.r<b.r:a.l<b.l;
}
bool cmp2(const node &a,const node &b)
{
return a.r==b.r?a.l<b.l:a.r<b.r;
}
void update(int x,int val)
{
while(x<maxn) c[x]+=val,x+=lowbit(x);
}
ll query(int x)
{
ll res=0;
while(x>0) res+=c[x],x-=lowbit(x);
return res;
}
int main()
{
int n,m,maxx=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i)
scanf("%d",&a[i]),pos[a[i]]=i,maxx=max(maxx,a[i]);
for(int i=1;i<=m;++i)
{
scanf("%d %d",&s1[i].l,&s1[i].r);
s1[i].id=i;
s2[i]=s1[i];
}
sort(s1+1,s1+1+m,cmp1);
sort(s2+1,s2+1+m,cmp2);
int pos1=1,pos2=1;
for(int i=1;i<=n;++i)
{
while(pos1<=m&&s1[pos1].l==i) ans[s1[pos1].id]-=query(s1[pos1].r)-query(s1[pos1].l-1),pos1++;
for(int j=a[i];j<=maxx;j+=a[i]) update(pos[j],1);
while(pos2<=m&&s2[pos2].r==i) ans[s2[pos2].id]+=query(s2[pos2].r)-query(s2[pos2].l-1),pos2++;
}
for(int i=1;i<=m;++i) printf("%lld\n",ans[i]);
}