给定:
两个长度为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]互不相等
思路:我们按询问的右端点排序,每次把<=r的点都加进来,加进来的同时因为m比较小,所以枚举把可能的另一半找出来,如果另一半在当前位置左边就更新维护左边这个位置,这样每次查询就一定是符合的。
代码:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e5+5;
const int N = 1e5;
int a[maxn], b[maxn], idx[maxn], k[maxn], bl[maxn], br[maxn];
int n, m, q;
struct node
{
int l, r, id;
bool operator <(const node &a) const
{
return r < a.r;
}
}op[maxn];
int tree[maxn], ans[maxn];
void pushUp(int root)
{
tree[root] = max(tree[root*2], tree[root*2+1]);
}
void update(int root, int l, int r, int pos, int val)
{
if(l == r)
{
tree[root] = max(tree[root], val);
return ;
}
int mid = (l+r)/2;
if(pos <= mid) update(root*2, l, mid, pos, val);
else update(root*2+1, mid+1, r, pos, val);
pushUp(root);
}
int query(int root, int l, int r, int i, int j)
{
if(i <= l && j >= r)
return tree[root];
int mid = (l+r)/2;
int mmax = 0;
if(i <= mid) mmax = max(mmax, query(root*2, l, mid, i, j));
if(j > mid) mmax = max(mmax, query(root*2+1, mid+1, r, i, j));
return mmax;
}
int main(void)
{
while(cin >> n >> q >> m)
{
memset(tree, 0, sizeof(tree));
memset(idx, -1, sizeof(idx));
for(int i = 1; i <= n; i++)
scanf("%d", &a[i]);
for(int i = 1; i <= n; i++)
scanf("%d", &b[i]), b[i] += N, idx[b[i]] = i;
for(int i = 1; i <= m; i++)
scanf("%d", &k[i]);
for(int i = 1; i <= q; i++)
scanf("%d%d", &op[i].l, &op[i].r), op[i].id = i;
sort(op+1, op+1+q);
int p = 1;
for(int i = 1; i <= q; i++)
{
while(p <= op[i].r)
{
for(int j = 1; j <= m; j++)
{
int pos = idx[b[p]+k[j]];
if(pos != -1 && pos <= p)
update(1, 1, n, pos, a[p]+a[pos]);
pos = idx[b[p]-k[j]];
if(pos != -1 && pos <= p)
update(1, 1, n, pos, a[p]+a[pos]);
}
p++;
}
ans[op[i].id] = query(1, 1, n, op[i].l, op[i].r);
}
for(int i = 1; i <= q; i++)
printf("%d\n", ans[i]);
}
return 0;
}