51nod 1463:找朋友 线段树

来源:互联网 发布:软件体系结构报告 编辑:程序博客网 时间:2024/05/21 22:28

1463 找朋友
基准时间限制:1.5 秒 空间限制:262144 KB 分值: 80 难度:5级算法题
 收藏
 取消关注
给定:
两个长度为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 mA1 A2 ....AnB1 B2 ....BnK1 K2 ....Kml1 r1l2 r2..lQ rQ
Output
Q行,每行一个整数表示相对应的答案。如果找不到这样的两个数则输出0。
Input示例
4 2 21 2 3 43 2 1 41 31 42 3
Output示例
75

这个题真算是涨了见识了。本来线段树的题自己切的实在太少,题目出来的时候根本不知道怎么做,看了题解跟厕神交流了之后才明白过来原来是这样节省时间的。

离线处理所有询问,按照右端点的顺序排序,这样做的目的是当前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;}



0 0
原创粉丝点击