给定:
两个长度为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]互不相等
线段树萌新看到这题就懵了……果然还是不行啊quq,然后就上网找到了题解和dalao的代码,认真参悟一番,终于A啦~
思路
题目说是很多询问,问最大值,看起来就很线段树。
要写线段树的话,我们就要想好,究竟是用线段树维护什么呢。
在这道题里,应该是维护当前位置pos的最大值。
这样的话,查询就只需要查询询问中l-r的最大值就阔以啦。
但还是有一点点问题~
这个最大值是会被各种东西影响的,比如bi的另一半在不在询问区间啦之类的。
所以我们需要离线!
将所有询问区间按右端点排序,然后逐个询问地加入每个点。每次都从上一次的r加到这一次的r。假设这个从r到r的循环的变量是j吧~
因为k的个数比较少,可以遍历每一个k,在保证bj满足区间要求的情况下遍历每个k,求出满足要求的另一个b。
因为j一定是满足要求的(j在右区间内,而右区间是不断扩张的,前边满足要求的不会影响后边的),这样判断某个点的最大值可行与否的时候,只需要判断它左边的部分是否满足要求就可以啦。
所以维护的当前位置pos的最大值,其实也就是左端点(bi)为pos的最大值
m
a
x
(
a
i
+
a
j
)
max(a_i+a_j)
max(ai+aj)啦~
我错过的一些细节
变量名称循环范围打错什么的就不提了。。。
那好像也没什么了。。
哦对了,这题的update和正常的不太一样。。
这棵线段树的update是将pos及它的列祖列宗的最大值都更新了,感觉是不可以用lazytag呢。(话说只更新
l
o
g
n
logn
logn个结点还lazy的话也太lazy了。。)(好像是因为是单点更新?)
不可以,而且莫得必要。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N = 100010;
ll n,m,w[N],a[N],b[N],bpos[N],K[15],ans[N<<2],tag[N<<2],Q,tans[N],re[N],res;
struct node{
ll l,r,xb;
}Que[100010];
bool cmp(node a,node b){
return a.r<b.r;
}
vector<int> g[N];
inline ll ls(ll x){return x<<1;}
inline ll rs(ll x){return x<<1|1;}
inline void update(ll pos,ll l,ll r,ll p,ll k){
// nl~nr的最大值修改为max(原来的,k)
ans[p] = max(k,ans[p]);
if(l == r) return;
ll mid = (l+r)>>1;
if(pos <= mid)
update(pos,l,mid,ls(p),k);
else update(pos,mid+1,r,rs(p),k);
}
void query(ll q_x,ll q_y,ll l,ll r,ll p){
if(q_x <= l&&r <= q_y) {
res = max(res,ans[p]);
return;
}
ll mid = (l+r)>>1;
if(q_x <= mid) query(q_x,q_y,l,mid,ls(p));
if(q_y > mid) query(q_x,q_y,mid+1,r,rs(p));
return;
}
int main(){
freopen("1.in","r",stdin);
scanf("%lld%lld%lld",&n,&Q,&m);
for(int i = 1;i <= n;i ++) scanf("%lld",&a[i]);
for(int i = 1;i <= n;i ++) scanf("%lld",&b[i]),bpos[b[i]] = i;
for(int i = 1;i <= m;i ++) scanf("%lld",&K[i]);
for(int i = 0;i < Q;i ++) scanf("%lld%lld",&Que[i].l,&Que[i].r),Que[i].xb = i;
sort(Que,Que+Q,cmp);
memset(re,0,sizeof re);
memset(ans,0,sizeof ans);
ll s=1,l,r,b2,b2pos;
for(int i = 0;i < Q;i ++){
l = Que[i].l;
r = Que[i].r;
for(ll j = s;j <= r;j ++){
for(int k = 1;k <= m;k ++){
b2 = b[j] + K[k];
if(b2 <= n){ //防止下一条越界
b2pos = bpos[b2];
if(b2pos < j && a[b2pos]+a[j] > re[b2pos]){
//更新前边的最大值。为什么不和re[j]比较?
//因为更新的时候会从小更新到大.
re[b2pos] = a[b2pos] + a[j];
update(b2pos,1,n,1,re[b2pos]);
}
}
b2 = b[j] - K[k];
if(b2 >= 1){
b2pos = bpos[b2];
if(b2pos < j && a[b2pos]+a[j] > re[b2pos]){
re[b2pos] = a[b2pos] + a[j];
update(b2pos,1,n,1,re[b2pos]);
}
}
}
}
res = 0;
query(l,r,1,n,1);
tans[Que[i].xb] = res;
s = r;
}
for(int i = 0;i < Q;i ++)
printf("%lld\n",tans[i]);
return 0;
}