这道题需要1些莫队算法的知识
定义记号f(A,B)表示询问区间A,B时的答案
用记号+表示集合的并
利用莫队算法我们可以计算出任意f(A,A)的值
无妨假定A=[l1,r1],B=[l2,r2],C=[r1+1,l2?1]
容易知道f(A,B)=f(A+B+C,A+B+C)+f(C,C)?f(A+C,A+C)?f(C+B,C+B)
因此1个询问被拆成4个可以用莫队算法做的询问
总的时间复杂度为O(msqrt(n))
(以上是官方题解)
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
using namespace std;
typedef long long LL;
const int N = 30000*4 + 10;
int pos[N];
struct pp{
int l,r,id;
int ans;
}p[N];
int cmp(pp a,pp b){
if(pos[a.l]==pos[b.l]) return a.r < b.r;
return a.l < b.l;
}
int cmp2(pp a,pp b){
return a.id < b.id;
}
struct que{
int l1,l2,r1,r2;
}q[N];
int block,n,k,m,num;
int a[N],cnt[N],answer;
LL x;
map<LL,int> mm;
void update(int x,int v){
int val = k - a[x];
if(val <= 0) return ;
answer += cnt[val]*v;
cnt[a[x]] += v;
}
void solve(){
int l,r;
answer = 0;
for(int i=1,l=1,r=0;i<=num;i++){//按块进行更新
for(;r<p[i].r;r++)
update(r+1,1);
for(;r>p[i].r;r--)
update(r,⑴);
for(;l<p[i].l;l++)
update(l,⑴);
for(;l>p[i].l;l--)
update(l⑴,1);
p[i].ans = answer;
}
}
int main(){
while(scanf("%d",&n)!=EOF){
mm.clear();
num = 0;
block = (int)sqrt(n)+1;
for(int i=1;i<=n;i++) pos[i] = i/block + 1;
scanf("%d",&k);
memset(cnt,0,sizeof(cnt));
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
scanf("%d",&m);
for(int i=1;i<=m;i++){
int l1,l2,r1,r2;
scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
q[i].l1 = l1 , q[i].r1 = r1 , q[i].l2 = l2 , q[i].r2 = r2;
p[++num].l = l1 , p[num].r = l2⑴ ;
x = l1*40000+(l2⑴);
mm[x] = num;
p[num].id = num;
p[++num].l = r1+1 , p[num].r = r2 ;
x = (r1+1)*40000+r2;
mm[x] = num;
p[num].id = num;
if(l2⑴ >= r1+1){
p[++num].l = r1+1 , p[num].r = l2⑴ ;
x = (r1+1)*40000+(l2⑴);
mm[x] = num;
p[num].id = num;
}
p[++num].l = l1 , p[num].r = r2 ;
x = l1*40000+r2;
mm[x] = num;
p[num].id = num;
}
sort(p+1,p+1+num,cmp);
solve();
sort(p+1,p+1+num,cmp2);
for(int i=1;i<=m;i++){
int l1,l2,r1,r2;
l1 = q[i].l1 , l2 = q[i].l2 , r1 = q[i].r1 , r2 = q[i].r2 ;
LL ans = 0;
x = l1*40000+r2;
ans += p[mm[x]].ans;
if(l2⑴>=r1+1){
x = (r1+1)*40000+(l2⑴);
ans += p[mm[x]].ans;
}
x = (r1+1)*40000+r2;
ans -= p[mm[x]].ans;
x = l1*40000+(l2⑴);
ans -= p[mm[x]].ans;
printf("%lld
",ans);
}
}
return 0;
}