您的位置:首页 > 其它

51nod 1463找朋友

2016-12-23 22:06 218 查看
给定:

两个长度为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

一开始根据b<=n直接就想到可以把所有的可行的BI,BJ全部求出来然后直接更新?然而没想到有什么数据结构能这么做。。

不得不看一波题解,感觉思路很巧妙。

先把询问按照右端点排序,然后每次左边界是固定的,所以只用考虑右边界,每次把范围内的合法对求出来然后在线段树里更新,注意这里的更新和普通的更新不同,因为线段树里存储的所有店实际上是1-i的区间最大答案,所以只要区间小于更新点的点全部都要更新,具体看代码。

uses math;
type node=record
l,r,id:longint;
end;
var
i,j,k,p,n,m,s,t,res,x,y:longint;
b,a,c,tr,ans,re,d:array[0..400000]of int64;
q:array[0..400000]of node;
procedure qsort(l,r:longint);
var
i,j,m:longint;
t:node;
begin
i:=l;
j:=r;
m:=q[(l+r)div 2].r;
repeat
while q[i].r<m do inc(i);
while q[j].r>m do dec(j);
if i<=j then
begin
t:=q[i];
q[i]:=q[j];
q[j]:=t;
inc(i);
dec(j);
end;
until i>j;
if l<j then qsort(l,j);
if i<r then qsort(i,r);
end;
procedure insert(x,l,r,num,v:longint);
var
m:longint;
begin
tr[x]:=max(tr[x],v);
if (l=num)and(r=num)then exit;
m:=(l+r)div 2;
if num<=m then insert(x*2,l,m,num,v)
else if num>m then insert(x*2+1,m+1,r,num,v);
end;
procedure find(x,l,r,l1,r1:longint);
var
m:longint;
begin
if (l=l1)and(r=r1)then
begin
res:=max(tr[x],res);
exit;
end;
m:=(l+r)div 2;
if r1<=m then find(x*2,l,m,l1,r1)
else if l1>m then find(x*2+1,m+1,r,l1,r1)
else begin
find(x*2,l,m,l1,m);
find(x*2+1,m+1,r,m+1,r1);
end;
end;
begin
readln(n,t,m);
fillchar(re,sizeof(re),0);
fillchar(c,sizeof(c),0);
for i:=1 to n do read(a[i]);
for i:=1 to n do
begin
read(b[i]);
c[b[i]]:=i;
end;
for i:=1 to m do read(d[i]);
for i:=1 to t do
begin
read(q[i].l,q[i].r);
q[i].id:=i;
end;
qsort(1,t);

s:=1;
for i:=1 to t do
begin
for j:=s to q[i].r do
begin
for k:=1 to m do
begin
x:=b[j]+d[k];
if x<=n then
y:=c[x];
if (x<=n)and(y<j)and(a[j]+a[y]>re[y])then
begin
re[y]:=a[j]+a[y];
insert(1,1,n,y,re[y]);
end;
x:=b[j]-d[k];
if x<0 then continue;
y:=c[x];
if (x>=1)and(y<j)and(a[j]+a[y]>re[y])then
begin
re[y]:=a[j]+a[y];
insert(1,1,n,y,re[y]);
end;
end;
end;
res:=0;
find(1,1,n,q[i].l,q[i].r);
ans[q[i].id]:=res;
s:=q[i].r;
end;
for i:=1 to t do writeln(ans[i]);
end.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  51nod 线段树