给出 n 个数和数字 k,有 m 此询问,每次给出两个区间 [l,r] [u,v] ,问每次询问时,从两个区间内各选一个数字 x,y ,问有多少个二元组使得 x+y=k 成立
本来是打算直接用两个莫队来维护这两个区间,但是超时了,想想也是,有 e7 的级数
这个题可以将这两个区间和并,因为注意到 l,r,u,v 的关系是单调递增的,所以合并之后用一个莫队来解决,为了满足题目中所说,分别从两个区间中选择 x,y ,所以从区间 [r+1,v] 和 [l,u-1] 中选择的另一个数字是不合法的,所以要从总数中减去,又根据容斥原理,[r+1,u-1] 这个区间被减了两次,所以要重新加回来
最后别忘了询问数组要开4倍
const int N=3e4+5;
int i,j,k;
int n,m,t;
int a[N];
struct Node
{
int l,r;
int bel,id,tag;
Node(int l=0,int r=0,int tag=0,int bel=0,int id=0):l(l),r(r),tag(tag),bel(bel),id(id){}
bool operator<(Node o){
if(bel==o.bel) return r<o.r;
return l<o.l;
}
}q[N<<2];
int cnt[N],cur,ans[N],block;
void add(int pos)
{
int x=a[pos];
if(k-x>0 && k-x<n) cur+=cnt[k-x];
if(x>0 && x<=n) cnt[x]++;
}
void del(int pos)
{
int x=a[pos];
if(x>0 && x<=n) cnt[x]--;
if(k-x>0 && k-x<n) cur-=cnt[k-x];
}
int main()
{
//IOS;
while(~sdd(n,k)){
for(int i=1;i<=n;i++) sd(a[i]),cnt[i]=0;
sd(m); block=sqrt(n);
int num=1,l,r,u,v;
for(int i=1;i<=m;i++){
sdd(l,r); sdd(u,v);
ans[i]=0;
q[num++]=Node(l,v,1,l/block,i);
q[num++]=Node(r+1,v,-1,(r+1)/block,i);
q[num++]=Node(l,u-1,-1,l/block,i);
q[num++]=Node(r+1,u-1,1,(r+1)/block,i);
}
sort(q+1,q+num);
l=1,r=0; cur=0;
for(int i=1;i<num;i++){
while(l>q[i].l) add(--l);
while(l<q[i].l) del(l++);
while(r>q[i].r) del(r--);
while(r<q[i].r) add(++r);
ans[q[i].id]+=cur*q[i].tag;
}
for(int i=1;i<=m;i++) pd(ans[i]);
}
//PAUSE;
return 0;
}