51nod 1463找朋友

给定:
两个长度为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.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值