CF301D Yaroslav and Divisors(树状数组)

对于询问离线,我们询问的是数对,并且所有的数字都是不同的,因此可以将数对的贡献放在位置靠前的位置

这样就是按照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;
    }
}
View Code
没有人不辛苦,只有人不喊疼
原文地址:https://www.cnblogs.com/ctyakwf/p/13944537.html