给定:
两个长度为n的数列A 、B
一个有m个元素的集合K
询问Q次
每次询问[l,r],输出区间内满足|Bi-Bj|∈K 的最大Ai+Aj

数据约定:
n,Q<=100000
m <= 10
0<=A[i]<=1000000000
1<=B[i]<=n
1<=K[i]<=n
保证B[i]互不相等
输入
n Q m
A1 A2 …An
B1 B2 …Bn
K1 K2 …Km
l1 r1
l2 r2
.
.
lQ rQ

输出
Q行,每行一个整数表示相对应的答案。
如果找不到这样的两个数则输出0。
输入样例
4 2 2
1 2 3 4
3 2 1 4
1 3
1 4
2 3
输出样例
7
5


考虑离线之后的做法。我们我们要做的就是把满足关系的放到线段树或者树状数组中。

我们可以注意到,m是很小的,所以我们枚举即可,处理出每个值所在的位置。

然后枚举集合当中每个元素,是否当前的元素组合之后可以等于,然后再把总和ai+aj放到线段树的左端点。


AC代码:

#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
int n,Q,m,a[N],b[N],pos[N],k[N],res[N];
struct node{int l,r,id;}q[N];
struct seg{int l,r,mx;}t[N<<2];
int cmp(node a,node b){return a.r<b.r;}
inline void push_up(int p){t[p].mx=max(t[p<<1].mx,t[p<<1|1].mx);}
void build(int p,int l,int r){
	t[p].l=l; t[p].r=r;
	if(l==r)	return ; int mid=l+r>>1;
	build(p<<1,l,mid);	build(p<<1|1,mid+1,r);
}
void change(int p,int x,int v){
	if(t[p].l==t[p].r)	return void(t[p].mx=max(t[p].mx,v));
	int mid=t[p].l+t[p].r>>1;
	if(x<=mid)	change(p<<1,x,v);
	else change(p<<1|1,x,v);
	push_up(p);
}
int ask(int p,int l,int r){
	if(t[p].l==l&&t[p].r==r)	return t[p].mx;
	int mid=t[p].l+t[p].r>>1;
	if(r<=mid)	return ask(p<<1,l,r);
	else if(l>mid)	return ask(p<<1|1,l,r);
	else	return max(ask(p<<1,l,mid),ask(p<<1|1,mid+1,r));
}
signed main(){
	cin>>n>>Q>>m;
	for(int i=1;i<=n;i++)	scanf("%lld",&a[i]);
	for(int i=1;i<=n;i++)	scanf("%lld",&b[i]),pos[b[i]]=i;
	for(int i=1;i<=m;i++)	scanf("%lld",&k[i]);
	for(int i=1;i<=Q;i++)	scanf("%lld %lld",&q[i].l,&q[i].r),q[i].id=i;
	sort(q+1,q+1+Q,cmp); build(1,1,n);	int j=1;
	for(int i=1;i<=Q;i++){
		for(;j<=q[i].r;j++){
			for(int s=1;s<=m;s++){
				if(b[j]+k[s]<=n&&pos[b[j]+k[s]]<j)	
					change(1,pos[b[j]+k[s]],a[j]+a[pos[b[j]+k[s]]]);
				if(b[j]-k[s]>=1&&pos[b[j]-k[s]]<j)
					change(1,pos[b[j]-k[s]],a[j]+a[pos[b[j]-k[s]]]);
			}
		}
		res[q[i].id]=ask(1,q[i].l,q[i].r);
	}
	for(int i=1;i<=Q;i++)	cout<<res[i]<<endl;
	return 0;
}