您的位置:首页 > 其它

51nod 1463:找朋友 线段树

2015-12-07 22:26 357 查看
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 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: