首页 > 代码库 > 【LOJ2254】SNOI2017一个简单的询问

【LOJ2254】SNOI2017一个简单的询问

莫队,每次询问的是两个区间,就把区间拆开,分开来算就好了。

借鉴了rank1大佬的玄学排询问的姿势。

#include<bits/stdc++.h>
#define N 50010
typedef long long ll;
using namespace std;
inline int read(){
    int f=1,x=0;char ch;
    do{ch=getchar();if(ch==-)f=-1;}while(ch<0||ch>9);
    do{x=x*10+ch-0;ch=getchar();}while(ch>=0&&ch<=9);
    return f*x;
}
int c1[N],c2[N],a[N],n,m,cnt;
struct Query{
    int l,r,id;
    bool operator < (const Query &ths) const {
        if(l/233!=ths.l/233) return l<ths.l;
        if(l/233&1) return r>ths.r;
        else return r<ths.r;
    }
}q[N<<2];
ll ans[N],tot=0,Ans=0;
int main(){
    n=read();for(int i=1;i<=n;i++)a[i]=read();
    m=read();
    for(int i=1;i<=m;i++){
        int l1=read(),r1=read(),l2=read(),r2=read();
        q[++cnt]=(Query){r1,r2,i};
        if(l1>1)q[++cnt]=(Query){l1-1,r2,-i};
        if(l2>1)q[++cnt]=(Query){l2-1,r1,-i};
        if(l1>1&&l2>1)q[++cnt]=(Query){l1-1,l2-1,i};
    }
    for(int i=1;i<=cnt;i++)if(q[i].l>q[i].r)swap(q[i].l,q[i].r);
    sort(q+1,q+cnt+1);
    int l=1,r=0;c1[a[1]]++;
    for(int i=1;i<=cnt;i++){
        while(r<q[i].r)r++,Ans+=c1[a[r]],c2[a[r]]++;
        while(l<q[i].l)l++,Ans+=c2[a[l]],c1[a[l]]++;
        while(r>q[i].r)Ans-=c1[a[r]],c2[a[r]]--,r--;
        while(l>q[i].l)Ans-=c2[a[l]],c1[a[l]]--,l--;
        if(q[i].id<0) ans[-q[i].id]-=Ans;
        else ans[q[i].id]+=Ans;
    }
    for(int i=1;i<=m;i++)printf("%lld\n",ans[i]);
}

 

【LOJ2254】SNOI2017一个简单的询问