Description
给定:
两个长度为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]互不相等
Solution
这是一道需要认真看题的题目。
因为要询问[l,r],所以我们可以考虑一下离线然后限制一个范围。
我们把l倒着排序,不断地减小,限制左边界。
然后,每次增加一个值,那么对其有影响的只有±k,而且看看题目,保证每个b不相等而且都不大于n,那么直接±k然后更新一个f[i]表示l到i的最大值,就好了。
因为还要求一个区间最大值,而且不用加减,所以用树状数组就可以了。
Code
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
using namespace std;
const int maxn=1e5+7;
int i,j,l,n,m,ans[maxn],k[11],q,p;
int a[maxn],b[maxn],c[maxn];
int t[maxn],f[maxn];
struct node{
int l,r,c;
}wen[maxn];
bool cmp(node x,node y){return x.l>y.l;}
int lowbit(int x){return x&(-x);}
void add(int x,int z){
if(x<0||x>n||c[x]<i)return;
int p=a[c[x]];x=c[x];
for(;x<=n;x+=lowbit(x))t[x]=max(t[x],p+z);
}
int find(int x){
int z=0;
for(;x;x-=lowbit(x))z=max(z,t[x]);
return z;
}
int main(){
// freopen("data.in","r",stdin);
// freopen("fan.in","r",stdin);
// freopen("fan.out","w",stdout);
scanf("%d%d%d",&n,&q,&m);
fo(i,1,n)scanf("%d",&a[i]);
fo(i,1,n)scanf("%d",&b[i]),c[b[i]]=i;
fo(i,1,m)scanf("%d",&k[i]);
fo(i,1,q)scanf("%d%d",&wen[i].l,&wen[i].r),wen[i].c=i;
sort(wen+1,wen+1+q,cmp);
l=n+1;
fo(j,1,q){
fod(i,l-1,wen[j].l){
fo(p,1,m){
add(b[i]-k[p],a[i]);
add(b[i]+k[p],a[i]);
l=l;
}
}
l=wen[j].l;
ans[wen[j].c]=find(wen[j].r);
}
fo(i,1,q)printf("%d\n",ans[i]);
}