題解 [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]互不相等
具體做法與心路歷程
這是線段樹的一道好題。類似題目有HH 的項鍊。
想的時候就覺得做法可能跟HH的項鍊比較像,最後差一點就想出來了,還是看了題解。
這種題還是要多想一想。
具體做法
題目告訴了我們是一個排列,且,我們考慮對每個數來做。
枚舉,我們可以快速算出與可以組成合法配對的另一個,若我們對於每個都只考慮在其左邊的情況,那麼可以做到不重不漏。
把詢問離線下來,按排序。考慮在枚舉的時候統計所有的詢問的答案。
我們把的值用線段樹存在的位置(在左邊),那麼詢問區間時相當於詢問的最大值。
這樣掃一遍即可。時間複雜度爲。
/*******************************
Author:galaxy yr
LANG:C++
Created Time:2019年10月29日 星期二 19時56分59秒
*******************************/
#include<cstdio>
#include<algorithm>
using namespace std;
struct IO{
template<typename T>
IO & operator>>(T&res)
{
T q=1;char ch;
while((ch=getchar())<'0' or ch>'9')if(ch=='-')q=-q;
res=(ch^48);
while((ch=getchar())>='0' and ch<='9') res=(res<<1)+(res<<3)+(ch^48);
res*=q;
return *this;
}
}cin;
struct Query{
int l,r,id;
bool operator<(const Query & p) const
{
return r<p.r;
}
};
const int maxn=1e5+10;
int a[maxn],b[maxn],n,m,q,s[11],ans[maxn],loc[maxn];
Query qry[maxn];
/*{{{線段樹*/
namespace SegmentTree{
int tr[maxn*4];
void update(int k)
{
tr[k]=max(tr[k<<1],tr[k<<1|1]);
}
void modify(int k,int l,int r,int pos,int val)
{
if(l==r)
{
tr[k]=max(tr[k],val);
return;
}
int mid=(l+r)>>1;
if(pos<=mid)
modify(k<<1,l,mid,pos,val);
else
modify(k<<1|1,mid+1,r,pos,val);
update(k);
}
int query(int k,int l,int r,int x,int y)
{
if(l>=x && r<=y) return tr[k];
if(l>y || r<x) return 0;
int mid=(l+r)>>1;
return max(query(k<<1,l,mid,x,y),query(k<<1|1,mid+1,r,x,y));
}
};
/*}}}*/
void solve()
{
int r=1;
for(int i=1;i<=n;i++)
{
for(int k=1;k<=m;k++)
{
if(b[i]>s[k] && loc[b[i]-s[k]]<=i)
SegmentTree::modify(1,1,n,loc[b[i]-s[k]],a[i]+a[loc[b[i]-s[k]]]);
if(b[i]+s[k]<=n && loc[b[i]+s[k]]<=i)
SegmentTree::modify(1,1,n,loc[b[i]+s[k]],a[i]+a[loc[b[i]+s[k]]]);
}
while(r<=q && qry[r].r<=i)
{
ans[qry[r].id]=SegmentTree::query(1,1,n,qry[r].l,qry[r].r);
r++;
}
}
}
int main()
{
//freopen("p1463.in","r",stdin);
//freopen("p1463.out","w",stdout);
cin>>n>>q>>m;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=n;i++) cin>>b[i],loc[b[i]]=i;
for(int i=1;i<=m;i++) cin>>s[i];
for(int i=1;i<=q;i++) cin>>qry[i].l>>qry[i].r,qry[i].id=i;
sort(qry+1,qry+q+1);
solve();
for(int i=1;i<=q;i++)
printf("%d\n",ans[i]);
return 0;
}