bzoj5016 一个简单的询问

这种不可直接做的问题

数据范围又很小

考虑莫队

但是,l1,l2,r1,r2四维?

考虑把询问二维差分!

f(a,b)表示,询问[1,a],[1, b]的答案

所以,ans(l1,r1,l2,y2)=f(r1,r2)-f(l1-1,r2)-f(r1,l2-1)+f(l1-1,l2-1)

正确性的话,考虑每一个种类k被统计的情况,c*d=(a+b)*(c+d)-a*(c+d)-c*(a+b)+a*b

需要离散化

数组开4倍

#include<bits/stdc++.h>
#define il inline
#define reg register int
#define numb (ch^'0')
using namespace std;
typedef long long ll;
il void rd(int &x){
    char ch;bool fl=false;
    while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
    for(x=numb;isdigit(ch=getchar());x=x*10+numb);
    (fl==true)&&(x=-x);
}
namespace Miracle{
const int N=50000+5;
int n,m;
int a[N];
int blo[N];
int b[N];
ll ans[N];
struct que{
    int l,r;
    int c,id;
    que(){}
    que(int ll,int rr,int cc,int dd){
        if(ll>rr) swap(ll,rr);
        l=ll;r=rr;c=cc;id=dd;
    }
    bool friend operator <(que a,que b){
        if(blo[a.l]==blo[b.l]){
            if(blo[a.l]&1) return a.r<b.r;
            return a.r>b.r;
        }
        return blo[a.l]<blo[b.l];
    }
}q[4*N];
int tot;
int buc[2][N];
ll now;
int l,r;
void dele(int d,int c){
    now-=buc[d^1][c];
    buc[d][c]--;
}
void add(int d,int c){
    now+=buc[d^1][c];
    buc[d][c]++;
}
void modui(){
    l=0;r=0;now=0;
    for(reg i=1;i<=tot;++i){
        while(l<q[i].l) ++l,add(0,a[l]);
        while(l>q[i].l) dele(0,a[l]),--l;
        while(r<q[i].r) ++r,add(1,a[r]);
        while(r>q[i].r) dele(1,a[r]),--r;
        ans[q[i].id]+=(ll)now*q[i].c;
    }
}
int main(){
    rd(n);
    for(reg i=1;i<=n;++i){
        rd(a[i]);
        blo[i]=(i-1)/223+1;
        b[i]=a[i];
    }
    sort(b+1,b+n+1);
    int cnt=unique(b+1,b+n+1)-b-1;
    for(reg i=1;i<=n;++i){
        a[i]=lower_bound(b+1,b+cnt+1,a[i])-b;
        //cout<<" a[i] "<<a[i]<<endl;
    }
    rd(m);
    int l1,l2,r1,r2;
    for(reg i=1;i<=m;++i){
        rd(l1);rd(r1);rd(l2);rd(r2);
        if(l1>1&&l2>1) q[++tot]=que(l1-1,l2-1,1,i);
        if(l1>1) q[++tot]=que(l1-1,r2,-1,i);
        if(l2>1) q[++tot]=que(r1,l2-1,-1,i);
        q[++tot]=que(r1,r2,1,i);
    }
    sort(q+1,q+tot+1);
    modui();
    for(reg i=1;i<=m;++i){
        printf("%lld\n",ans[i]);
    }
    return 0;
}

}
signed main(){
    Miracle::main();
    return 0;
}

/*
   Author: *Miracle*
   Date: 2019/1/27 22:24:01
*/

询问的二维拆分有点意思!

以前并没有遇到这种问题(最多就是一维差分)

之前莫队都是(l,r)这种

如果可以前缀差分的话,那么多个(li,ri)都是可以的

本质就是容斥,或者高维差分

猜你喜欢

转载自www.cnblogs.com/Miracevin/p/10331033.html