题目:点击打开链接
思路:
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;
}