题解 [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的项链比较像,最后差一点就想出来了,还是看了题解。
这种题还是要多想一想。
具体做法
题目告诉了我们 B B B是一个排列,且 m ≤ 10 m \leq 10 m≤10,我们考虑对每个数来做。
枚举 i i i,我们可以快速算出与 B i B_i Bi可以组成合法配对的另一个 B j B_j Bj,若我们对于每个 i i i都只考虑 j j j在其左边的情况,那么可以做到不重不漏。
把询问离线下来,按 r r r排序。考虑在枚举 i i i的时候统计所有 r = i r=i r=i的询问的答案。
我们把 A i + A j A_i+A_j Ai+Aj的值用线段树存在 j j j的位置( j j j在 i i i左边),那么询问区间时相当于询问 l , r l,r l,r的最大值。
这样扫一遍即可。时间复杂度为 O ( n m l o g n + q ) O(nmlogn+q) O(nmlogn+q)。
C o d e \mathcal{Code} Code
/*******************************
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;
}