[Snoi2017]一个简单的询问

Posted NamelessOIer

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Snoi2017]一个简单的询问相关的知识,希望对你有一定的参考价值。

数据范围很容易让人想到莫队算法
但是对于每次询问有\(l_1,r_1,l_2,r_2\)四个参数
很不方便维护
所以可以将询问差分

\(get(l,r,x)=get(1,r,x)-get(1,l-1,x)\)
\(get(l_1,r_1,x)*get(l_2,r_2,x)\)
\(=get(1,r_1,x)*get(1,r_2,x)\)
\(-get(1,l_1-1,x)*get(1,r_2,x)\)
\(-get(1,r_1,x)*get(1,l_2-1,x)\)
\(+get(1,l_1-1,x)*get(1,l_2-1,x)\)

于是原问题转化为四个只有两个参数的问题且可以使用莫队求解的问题

#include<bits/stdc++.h>

using namespace std;

#define gc c=getchar()
#define r(x) read(x)
#define ll long long

template<typename T>
inline void read(T&x){
    x=0;T k=1;char gc;
    while(!isdigit(c)){if(c==‘-‘)k=-1;gc;}
    while(isdigit(c)){x=x*10+c-‘0‘;gc;}x*=k;
}

const int N=50005;

int be[N],a[N];

struct Query{
    int l,r,type,id;
    bool operator < (Query x) const{
        return be[l]==be[x.l]?r<x.r:l<x.l;
    }
};

ll Ans[N];
vector<Query> Q;

int cntl[N],cntr[N];

int main(){
    int n,m;r(n);
    int block_size=sqrt(n);
    for(int i=1;i<=n;++i){
        r(a[i]);
        be[i]=(i-1)/block_size+1;
    }
    r(m);
    for(int i=1,l1,r1,l2,r2;i<=m;++i){
        r(l1),r(r1),r(l2),r(r2);
        Q.push_back(Query{r1,r2,1,i});
        if(l1>1)Q.push_back(Query{l1-1,r2,-1,i});
        if(l2>1)Q.push_back(Query{r1,l2-1,-1,i});
        if(l1>1&&l2>1)Q.push_back(Query{l1-1,l2-1,1,i});
    }
    sort(Q.begin(),Q.end());
    ll ans=0;
    int l=0,r=0;
    for(int i=0;i<Q.size();++i){
        Query &x=Q[i];
        
        while(l<x.l)cntl[a[++l]]++,ans+=cntr[a[l]];
        while(l>x.l)cntl[a[l]]--,ans-=cntr[a[l--]];
        while(r<x.r)cntr[a[++r]]++,ans+=cntl[a[r]];
        while(r>x.r)cntr[a[r]]--,ans-=cntl[a[r--]];
        
        Ans[x.id]+=x.type*ans;
    }
    for(int i=1;i<=m;++i)printf("%lld\n",Ans[i]);
}

以上是关于[Snoi2017]一个简单的询问的主要内容,如果未能解决你的问题,请参考以下文章

[Snoi2017]一个简单的询问

bzoj 5016: [Snoi2017]一个简单的询问

bzoj 5016 [Snoi2017]一个简单的询问

bzoj5016[Snoi2017]一个简单的询问 莫队算法

bzoj5019: [Snoi2017]遗失的答案

SNOI2017(BZOJ5015~5018)泛做