UESTC-1931 为什么你这么熟练啊(莫队)

题目:点击打开链接

思路:

    get(l1,r1,x)=get(1,r1,x)-get(1,l1-1,x);

    get(l2,r2,x)=get(1,r2,x)-get(1,l2-1,x);

    get(l1,r1,x)get(l2,r2,x)=get(l,r1,x)*get(1,r2,x)+get(1,l1-1,x)*get(1,l2-1,x)-get(1,r1,x)*get(1,l2-1,x)-get(1,l1-1,x)*get(1,r2,x);

那么,我们可以将一次询问划分为4个区间,(r1,r2),(l1-1,l2-1),(r1,l2-1),(l1-1,r2);

然后用莫队就可以顺利的过题了;

AC代码:

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define ll tree[rt].l
#define rr tree[rt].r
#define rs rt<<1|1
#define ls rt<<1
const int maxn=5e4+10;
const int inf=1e9+10;
const long long INF=2e18+10;
int n,a[maxn],q,lv[maxn],rv[maxn],bk,ans[maxn];
struct node{
    int l,r,tag,id;
    node(){};
    node(int l1,int r1,int t,int i){l=l1;r=r1;tag=t;id=i;}
    bool operator < (const node a) const {
        if((l-1)/bk==(a.l-1)/bk) return (r-1)/bk<(a.r-1)/bk;
        return (l-1)/bk>(a.l-1)/bk;
    }
};
vector<node> vec;
int main()
{
    scanf("%d",&n);
    bk=sqrt(n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    scanf("%d",&q);
    int l1,r1,l2,r2;
    for(int i=1;i<=q;i++){
        scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
        vec.push_back(node(r1,r2,1,i));
        vec.push_back(node(r1,l2-1,-1,i));
        vec.push_back(node(l1-1,r2,-1,i));
        vec.push_back(node(l1-1,l2-1,1,i));
    }
    sort(vec.begin(),vec.end());
    int L=0,R=0,cnt=0;
    for(int i=0;i<vec.size();i++){
        int l=vec[i].l,r=vec[i].r;
        while(L<l){
            L++;
            cnt+=rv[a[L]];
            lv[a[L]]++;
        }
        while(L>l){
            cnt-=rv[a[L]];
            lv[a[L]]--;
            L--;
        }
        while(R<r){
            R++;
            cnt+=lv[a[R]];
            rv[a[R]]++;
        }
        while(R>r){
            cnt-=lv[a[R]];
            rv[a[R]]--;
            R--;
        }
        ans[vec[i].id]+=vec[i].tag*cnt;
    }
    for(int i=1;i<=q;i++){
        printf("%d\n",ans[i]);
    }
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_37171272/article/details/81057138