CF.D Strange Queries

传送门

题意:n个整数\(a_1,a_2...a_n\),q个询问,每个询问包括四个整数\(l_1,r_1,l_2,r_2\),求满足下列三个条件的整数对\((i,j)\)de个数:

\(a_i=a_j\)

\(l_1<=i<=r_1\)

\(l_2<=j<=r_2\)

这道题其实就是道裸莫队,但前提是理解了这道题的意思.不妨看做有两个区间\([l_1,r_1],[l_2,r_2]\),我们要维护的就是这两个区间内每个数的个数,则根据题意,两个区间内相等的数的个数的乘积之和就是\(ans\).

于是我们按照普通莫队的做法,把每个询问以\(l_1,r_1\)为关键字排序,然后暴力维护\(l_2,r_2\)即可.

int n,m,t,l1=1,r1,l2=1,r2;
int a[50005],place[50005];
int tot1[50005],tot2[50005];
long long Ans,ans[50005];
struct A{
    int l1,r1,l2,r2,id;
}query[50001];
bool cmp(A x,A y){
    return place[x.l1]==place[y.l1]?x.r1<y.r1:x.l1<y.l1;
}
void change1(int x,int y){
    Ans-=(long long)tot1[x]*tot2[x];
    tot1[x]+=y;
    Ans+=(long long)tot1[x]*tot2[x];
}
void change2(int x,int y){
    Ans-=(long long)tot1[x]*tot2[x];
    tot2[x]+=y;
    Ans+=(long long)tot1[x]*tot2[x];
}
int main(){
    n=read();t=sqrt(n);
    for(int i=1;i<=n;i++)
        a[i]=read(),place[i]=i/t+1;
    m=read();
    for(int i=1;i<=m;i++){
        query[i].l1=read();query[i].r1=read();
        query[i].l2=read();query[i].r2=read();
        query[i].id=i;
    }
    sort(query+1,query+m+1,cmp);
    for(int i=1;i<=m;i++){
        while(l1<query[i].l1)change1(a[l1],-1),l1++;
        while(query[i].l1<l1)change1(a[l1-1],1),l1--;
        while(r1<query[i].r1)change1(a[r1+1],1),r1++;
        while(query[i].r1<r1)change1(a[r1],-1),r1--;
        while(l2<query[i].l2)change2(a[l2],-1),l2++;
        while(query[i].l2<l2)change2(a[l2-1],1),l2--;
        while(r2<query[i].r2)change2(a[r2+1],1),r2++;
        while(query[i].r2<r2)change2(a[r2],-1),r2--;
        ans[query[i].id]=Ans;
    }
    for(int i=1;i<=m;i++)
        printf("%lld\n",ans[i]);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/PPXppx/p/10327177.html
今日推荐