对于询问离线,我们询问的是数对,并且所有的数字都是不同的,因此可以将数对的贡献放在位置靠前的位置
这样就是按照r排序,之后遍历每个位置计算答案,为了避免之后当前r之后的信息干扰到目前答案的计算,我们枚举倍数的时候,如果这个数在当前位置i之后,那么就先将他保存
如果在之前,就直接用树状数组维护。这样我们所有的答案都是当前合法的。
#include<bits/stdc++.h> using namespace std; typedef long long ll; typedef pair<ll,ll> pll; const int N=4e6+10; const ll mod=998244353; struct node{ int l,r,id; }q[N]; int a[N]; int pos[N]; int tr[N]; int p[N]; int lowbit(int x){ return x&-x; } void add(int x,int c){ int i; for(i=x;i<N;i+=lowbit(i)){ tr[i]+=c; } } int sum(int x){ int i; int ans=0; for(i=x;i;i-=lowbit(i)){ ans+=tr[i]; } return ans; } bool cmp(node a,node b){ return a.r<b.r; } vector<int> num[N]; int ans[N]; int main(){ ios::sync_with_stdio(false); int n,m; cin>>n>>m; int i; for(i=1;i<=n;i++){ cin>>a[i]; pos[a[i]]=i; } for(i=1;i<=m;i++){ cin>>q[i].l>>q[i].r; q[i].id=i; } sort(q+1,q+1+m,cmp); int cur=1; for(i=1;i<=n;i++){ int tmp=a[i]; for(auto x:num[tmp]){ add(x,1); } for(int j=tmp;j<=n;j+=tmp){ int d=pos[j]; if(d<=i){ add(d,1); } else{ num[j].push_back(i); } } while(cur<=m&&q[cur].r==i){ ans[q[cur].id]=sum(q[cur].r)-sum(q[cur].l-1); cur++; } } for(i=1;i<=m;i++){ cout<<ans[i]<<endl; } }