题目描述
题目解法
解法1
这道题一个暴力的解法是枚举每个权值,然后用莫队暴力维护一下
时间复杂度 ,a是值域,可以得到80pts
解法2
这道题我们考虑拆分式子
我们可以借用前缀和的思想,把 变成
那么 可以变成
于是我们只需要考虑求解
我们可以借用莫队的思想来优化暴力
让k1和k2都只动 次,然后维护一下res就可以了
最后再把几个式子合起来就是答案
时间复杂度
这道题的一个启发就是:莫队不一定只是处理区间的问题,还可以借用莫队的思想优化暴力
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N(50100),M(50100);
struct Query{
int id,l,r,neg;
}query[M<<2];
int n,m,a[N],pos[N];
int cnt1[N],cnt2[N];
LL res,ans[M];
inline int read(){
int FF=0,RR=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar())
if(ch=='-')
RR=-1;
for(;isdigit(ch);ch=getchar())
FF=(FF<<1)+(FF<<3)+ch-48;
return FF*RR;
}
bool cmp(const Query &x,const Query &y){
if(pos[x.l]^pos[y.l])
return pos[x.l]<pos[y.l];
return pos[x.l]&1?x.r<y.r:x.r>y.r;
}
int main(){
n=read();
for(int i=1;i<=n;i++)
a[i]=read();
int B=sqrt(n);
for(int i=1;i<=n;i++)
pos[i]=(i-1)/B+1;
m=read();
for(int i=1,l1,r1,l2,r2;i<=m;i++){
l1=read(),r1=read(),l2=read(),r2=read();
query[(i<<2)-3]={i,r1,r2,1};
query[(i<<2)-2]={i,r1,l2-1,-1};
query[(i<<2)-1]={i,l1-1,r2,-1};
query[i<<2]={i,l1-1,l2-1,1};
}
sort(query+1,query+(m<<2)+1,cmp);
for(int k=1,i=0,j=0;k<=m<<2;k++){
int l=query[k].l,r=query[k].r;
while(j>r) res-=cnt1[a[j]],cnt2[a[j]]--,j--;
while(j<r) j++,res+=cnt1[a[j]],cnt2[a[j]]++;
while(i>l) res-=cnt2[a[i]],cnt1[a[i]]--,i--;
while(i<l) i++,res+=cnt2[a[i]],cnt1[a[i]]++;
ans[query[k].id]+=query[k].neg*res;
}
for(int i=1;i<=m;i++)
printf("%lld\n",ans[i]);
return 0;
}