给定:
两个长度为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]互不相等
Input
n Q m A1 A2 ....An B1 B2 ....Bn K1 K2 ....Km l1 r1 l2 r2 . . lQ rQ
Output
Q行,每行一个整数表示相对应的答案。 如果找不到这样的两个数则输出0。
Input示例
4 2 2 1 2 3 4 3 2 1 4 1 3 1 4 2 3
Output示例
7 5
这个题真算是涨了见识了。本来线段树的题自己切的实在太少,题目出来的时候根本不知道怎么做,看了题解跟厕神交流了之后才明白过来原来是这样节省时间的。
离线处理所有询问,按照右端点的顺序排序,这样做的目的是当前1到最远距离,这段区间里面的任何一个我只需要询问线段树即可,如果来了一个新的右端点的距离,那么每次我只需要不断向右拓展一段就好了。
每次向右拓展的话,就相当于新来了一个一个的元素,因为m的值很小,最多10。所以可以通过数组K,询问另一个元素是否在前面,如果发现在前面,看是否这两个数的和大于当前值,大于那么更新该点的值。
所以其实这个线段树每个节点存储的就只是当前节点与后面元素,在B数组满足相应关系下的,A数组的最大值。不用管前面了,前面的自然有相应的元素再管。
代码:
#pragma warning(disable:4996)
#include <iostream>
#include <algorithm>
#include <cmath>
#include <vector>
#include <string>
#include <cstring>
using namespace std;
const int maxn = 100005;
struct no
{
int L, R;
int nMax;
};
no tree[400005];
struct ques
{
int le;
int ri;
int pos;
bool operator<(const ques &n1)
{
return ri < n1.ri;
}
}qu[maxn];
int n, Q, m;
int res;
int A[maxn];
int B[maxn];
int K[maxn];
int appear[maxn];
int re[maxn];
int ans[maxn];
void build(int root, int le, int ri)
{
tree[root].L = le;
tree[root].R = ri;
tree[root].nMax = 0;
if (le == ri)return;
int mid = (le + ri) / 2;
build(root << 1, le, mid);
build((root << 1) + 1, mid + 1, ri);
}
void query(int root, int le, int ri)
{
if (tree[root].L == le&&tree[root].R == ri)
{
res = max(res, tree[root].nMax);
return;
}
int mid = (tree[root].L + tree[root].R) / 2;
if (ri <= mid)
{
query(root << 1, le, ri);
}
else if (le > mid)
{
query((root << 1) + 1, le, ri);
}
else
{
query(root << 1, le, mid);
query((root << 1) + 1, mid + 1, ri);
}
}
void insert(int root, int num, int val)
{
tree[root].nMax = max(tree[root].nMax, val);
if (tree[root].L == num&&tree[root].R == num)
{
return;
}
int mid = (tree[root].L + tree[root].R) / 2;
if (num <= mid)
{
insert(root << 1, num, val);
}
else if (num > mid)
{
insert((root << 1) + 1, num, val);
}
}
void input()
{
int i, j, k;
scanf("%d%d%d", &n, &Q, &m);
memset(appear, 0, sizeof(appear));
memset(re, 0, sizeof(re));
for (i = 1; i <= n; i++)
{
scanf("%d", &A[i]);
}
for (i = 1; i <= n; i++)
{
scanf("%d", &B[i]);
appear[B[i]] = i;
}
for (i = 1; i <= m; i++)
{
scanf("%d", &K[i]);
}
for (i = 1; i <= Q; i++)
{
scanf("%d%d", &qu[i].le, &qu[i].ri);
qu[i].pos = i;
}
}
void work()
{
sort(qu + 1, qu + Q + 1);
build(1, 1, n);
int s = 1;
int i, j, k;
for (i = 1; i <= Q; i++)
{
int r = qu[i].ri;
for (j = s; j <= r; j++)
{
for (k = 1; k <= m; k++)
{
int vv = B[j] + K[k];
int xyz = appear[vv];
if (vv <= n&&xyz<j&&A[xyz] + A[j]>re[xyz])
{
re[xyz] = A[xyz] + A[j];
insert(1, xyz, re[xyz]);
}
vv = B[j] - K[k];
xyz = appear[vv];
if (vv >= 1&& xyz<j&&A[xyz] + A[j]>re[xyz])
{
re[xyz] = A[xyz] + A[j];
insert(1, xyz, re[xyz]);
}
}
}
res = 0;
query(1, qu[i].le, qu[i].ri);
s = r;
ans[qu[i].pos] = res;
}
for (i = 1; i <= Q; i++)
{
printf("%d\n", ans[i]);
}
}
int main()
{
//freopen("i.txt", "r", stdin);
//freopen("o.txt", "w", stdout);
input();
work();
//system("pause");
return 0;
}