这种不可直接做的问题
数据范围又很小
考虑莫队
但是,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 ",ans[i]); } return 0; } } signed main(){ Miracle::main(); return 0; } /* Author: *Miracle* Date: 2019/1/27 22:24:01 */
询问的二维拆分有点意思!
以前并没有遇到这种问题(最多就是一维差分)
之前莫队都是(l,r)这种
如果可以前缀差分的话,那么多个(li,ri)都是可以的
本质就是容斥,或者高维差分