【51Nod 1463】找朋友

45 篇文章 0 订阅
18 篇文章 0 订阅

Description

给定:
两个长度为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]互不相等

Solution

这是一道需要认真看题的题目。
因为要询问[l,r],所以我们可以考虑一下离线然后限制一个范围。
我们把l倒着排序,不断地减小,限制左边界。
然后,每次增加一个值,那么对其有影响的只有±k,而且看看题目,保证每个b不相等而且都不大于n,那么直接±k然后更新一个f[i]表示l到i的最大值,就好了。
因为还要求一个区间最大值,而且不用加减,所以用树状数组就可以了。

Code

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<math.h>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
using namespace std;
const int maxn=1e5+7;
int i,j,l,n,m,ans[maxn],k[11],q,p;
int a[maxn],b[maxn],c[maxn];
int t[maxn],f[maxn];
struct node{
    int l,r,c;
}wen[maxn];
bool cmp(node x,node y){return x.l>y.l;}
int lowbit(int x){return x&(-x);}
void add(int x,int z){
    if(x<0||x>n||c[x]<i)return;
    int p=a[c[x]];x=c[x];
    for(;x<=n;x+=lowbit(x))t[x]=max(t[x],p+z);
}
int find(int x){
    int z=0;
    for(;x;x-=lowbit(x))z=max(z,t[x]);
    return z;
}
int main(){
//  freopen("data.in","r",stdin);
  //  freopen("fan.in","r",stdin);
//  freopen("fan.out","w",stdout);
    scanf("%d%d%d",&n,&q,&m);
    fo(i,1,n)scanf("%d",&a[i]);
    fo(i,1,n)scanf("%d",&b[i]),c[b[i]]=i;
    fo(i,1,m)scanf("%d",&k[i]);
    fo(i,1,q)scanf("%d%d",&wen[i].l,&wen[i].r),wen[i].c=i;
    sort(wen+1,wen+1+q,cmp);
    l=n+1;
    fo(j,1,q){
        fod(i,l-1,wen[j].l){
            fo(p,1,m){
                add(b[i]-k[p],a[i]);  
                add(b[i]+k[p],a[i]);  
                l=l;
            }    
        }    
        l=wen[j].l;
        ans[wen[j].c]=find(wen[j].r);
    }
    fo(i,1,q)printf("%d\n",ans[i]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值