51nod 1463 找朋友(线段树+离线处理)
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1463
题意:

思路:
好题!
先对所有查询进行离线处理,按照右区间排序,因为k一共最多只有10个,所有在该区间内的B数组,每次枚举K值,通过这样的方式来得到另外一个B值。但是这样得到的B值它在B数组中的位置必须在当前数的左边。如下图:(j为当前数在B数组中的位置,pos为计算得到的另一个B值在数组中的位置)

这两个数的和记录在pos中,这里pos的位置必须在j的左边,假设第q个查询区间如上图所示(请在脑中将pos和j互换一下),那么此时j就没包含在该区间内,这样一来,查询得到的值就会有错。因为我们是按照右区间排序的,所以右区间会不断扩大,只要左边被覆盖的,那么右边的数肯定是在该区间内的。
用线段树维护即可。具体请参见代码。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
#include<stack>
#include<queue>
#include<cmath>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int maxn=1e5+; int n,q,m;
int A[maxn],B[maxn],K[],B_pos[maxn],ans[maxn]; struct node
{
int l,r,id;
bool operator<(const node& rhs) const
{
return r<rhs.r;
}
}Q[maxn]; int MAX[maxn<<];
int val[maxn<<]; void build(int l, int r, int o)
{
val[o]=;
if(l==r) return;
int mid=(l+r)>>;
build(l,mid,o<<);
build(mid+,r,o<<|);
} void update(int l, int r, int pos, int x, int o)
{
val[o]=max(val[o],x);
if(l==pos && r==pos) return;
int mid=(l+r)>>;
if(pos<=mid) update(l,mid,pos,x,o<<);
else update(mid+,r,pos,x,o<<|);
} int query(int ql, int qr, int l, int r, int o)
{
if(ql<=l && qr>=r) return val[o];
int mid=(l+r)>>;
int res=;
if(ql<=mid) res=max(res,query(ql,qr,l,mid,o<<));
if(qr>mid) res=max(res,query(ql,qr,mid+,r,o<<|));
return res;
} int main()
{
//freopen("in.txt","r",stdin);
scanf("%d%d%d",&n,&q,&m);
for(int i=;i<=n;i++) scanf("%d",&A[i]);
for(int i=;i<=n;i++) {scanf("%d",&B[i]);B_pos[B[i]]=i;}
for(int i=;i<=m;i++) scanf("%d",&K[i]);
for(int i=;i<=q;i++)
{
scanf("%d%d",&Q[i].l,&Q[i].r);
Q[i].id=i;
}
sort(Q+,Q+q+);
build(,n,);
int s=;
memset(MAX,,sizeof(MAX));
for(int i=;i<=q;i++)
{
int r=Q[i].r;
for(int j=s;j<=r;j++)
{
for(int k=;k<=m;k++)
{
int tmp_B=B[j]+K[k];
int pos=B_pos[tmp_B]; //得到tmp_B在B数组中的位置
if(tmp_B<=n && pos<j && A[pos]+A[j]>MAX[pos])
{
MAX[pos]=A[pos]+A[j]; //此时pos位置的最大值是由pos和[1,j)之间的一个数相加而成
update(,n,pos,MAX[pos],); //更新线段树
}
tmp_B=B[j]-K[k];
pos=B_pos[tmp_B];
if(tmp_B>= && pos<j && A[pos]+A[j]>MAX[pos])
{
MAX[pos]=A[pos]+A[j];
update(,n,pos,MAX[pos],);
}
}
}
ans[Q[i].id]=query(Q[i].l,Q[i].r,,n,); //查询该区间内的最大值
s=r;
}
for(int i=;i<=q;i++) printf("%d\n",ans[i]);
return ;
}
再给一个树状数组的吧,按照左区间从大到小排序。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
#include<stack>
#include<queue>
#include<cmath>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int maxn=1e5+; int n,q,m;
int A[maxn],B[maxn],K[],B_pos[maxn],ans[maxn],c[maxn]; struct node
{
int l,r,id;
bool operator<(const node& rhs) const
{
return l>rhs.l;
}
}Q[maxn]; int lowbit(int x)
{
return x&(-x);
} int find_max(int x)
{
int res=;
while(x>)
{
res=max(res,c[x]);
x-=lowbit(x);
}
return res;
} void update(int x, int val)
{
while(x<=n)
{
c[x]=max(c[x],val);
x+=lowbit(x);
}
} int main()
{
//freopen("in.txt","r",stdin);
scanf("%d%d%d",&n,&q,&m);
for(int i=;i<=n;i++) scanf("%d",&A[i]);
for(int i=;i<=n;i++) {scanf("%d",&B[i]);B_pos[B[i]]=i;}
for(int i=;i<=m;i++) scanf("%d",&K[i]);
for(int i=;i<=q;i++)
{
scanf("%d%d",&Q[i].l,&Q[i].r);
Q[i].id=i;
}
sort(Q+,Q+q+);
memset(c,,sizeof(c));
int s=n+;
for(int i=;i<=q;i++)
{
for(int j=s-;j>=Q[i].l;j--)
{
for(int k=;k<=m;k++)
{
int tmp_B=B[j]+K[k];
int pos=B_pos[tmp_B];
if(tmp_B<=n && pos>j)
{
update(pos,A[pos]+A[j]);
}
tmp_B=B[j]-K[k];
pos=B_pos[tmp_B];
if(tmp_B>= && pos>j)
{
update(pos,A[pos]+A[j]);
}
}
}
s=Q[i].l;
ans[Q[i].id]=find_max(Q[i].r);
} for(int i=;i<=q;i++) printf("%d\n",ans[i]);
return ;
}
51nod 1463 找朋友(线段树+离线处理)的更多相关文章
- 51nod 1463 找朋友 (扫描线+线段树)
1463 找朋友 基准时间限制:1.5 秒 空间限制:262144 KB 分值: 80 难度:5级算法题 收藏 关注 给定: 两个长度为n的数列A .B 一个有m个元素的集合K 询问Q次 每次询 ...
- 线段树+离线 hdu5654 xiaoxin and his watermelon candy
传送门:点击打开链接 题意:一个三元组假设满足j=i+1,k=j+1,ai<=aj<=ak,那么就好的.如今告诉你序列.然后Q次询问.每次询问一个区间[l,r],问区间里有多少个三元组满足 ...
- 牛客练习赛53 E-老瞎眼pk小鲜肉(思维+线段树+离线)
前言 听说是线段树离线查询?? 做题做着做着慢慢对离线操作有点感觉了,不过也还没参透,等再做些题目再来讨论离线.在线操作. 这题赛后看代码发现有人用的树状数组,$tql$.当然能用树状数组写的线段树也 ...
- HDU 4638-Group(线段树+离线处理)
题意: 给n个编号,m个查询每个查询l,r,求下标区间[l,r]中能分成标号连续的组数(一组内的标号是连续的) 分析: 我们认为初始,每个标号为一个组(线段树维护区间组数),从左向右扫序列,当前标号, ...
- HDU 4630-No Pain No Game(线段树+离线处理)
题意: 给你n个数的序列a,q个询问,每个询问给l,r,求在下标i在[l,r]的区间任意两个数的最大公约数中的最大值 分析: 有了hdu3333经验,我们从左向右扫序列,如果当前数的约数在前面出现过, ...
- HDU 4288 Coder 【线段树+离线处理+离散化】
题意略. 离线处理,离散化.然后就是简单的线段树了.需要根据mod 5的值来维护.具体看代码了. /* 线段树+离散化+离线处理 */ #include <cstdio> #include ...
- SPOJ--K-query (线段树离线) 离线操作解决一些问题
K-query Given a sequence of n numbers a1, a2, ..., an and a number of k- queries. A k-query is a tri ...
- lca 欧拉序+rmq(st) 欧拉序+rmq(线段树) 离线dfs 倍增
https://www.luogu.org/problemnew/show/P3379 1.欧拉序+rmq(st) /* 在这里,对于一个数,选择最左边的 选择任意一个都可以,[left_index, ...
- 玲珑oj 1117 线段树+离线+离散化,laz大法
1117 - RE:从零开始的异世界生活 Time Limit:1s Memory Limit:256MByte Submissions:438Solved:68 DESCRIPTION 486到了异 ...
随机推荐
- C和C++不容易发现的区别
1.char指针指向字符串常量 当下面的代码写到.c文件中时,可以正常运行;而写到.cpp文件中就会报错:无法从“const char [6]”转换为“char *”. char * c = &quo ...
- for练习相关
for嵌套: 大圈套小圈思想:有一种重复的情况而这种情况每一次对应另外情况多次. ------------------------------------------------------- 例如: ...
- 实习培训——Java基础(2)
实习培训——Java基础(2) 1 Java 变量类型 在Java语言中,所有的变量在使用前必须声明.声明变量的基本格式如下: type identifier [ = value][, identi ...
- Hadoop集群安装-CDH5(5台服务器集群)
CDH5包下载:http://archive.cloudera.com/cdh5/ 架构设计: 主机规划: IP Host 部署模块 进程 192.168.254.151 Hadoop-NN-01 N ...
- iOS 常用小功能 总结
常用小功能 iOS中的很多小功能都是非常简单的,几行代码就搞定了,比如打电话.打开网址.发邮件.发短信等 打电话 方法一(不被采用): 拨号之前会弹框询问用户是否拨号,拨完后能自动回到原应用 NSUR ...
- c++虚函数重写的权限问题
cbase.h: #ifndef CBASE_H #define CBASE_H #include<iostream> using std::cout; using std::endl; ...
- !! A股历史平均市盈率走势图
http://value500.com/PE.asp 一. A股历史平均市盈率走势图 *数据来源:上海证券交易所 分享到: 354 - 上海A股 深圳A股更新时间 2017年6月7日 2017年6月7 ...
- Linux下的Make命令实例详解
众所周知在Linux系统下的make 命令是系统管理员和程序员用的最频繁的命令之一.管理员用它通过命令行来编译和安装很多开源的工具,程序员用它来管理他们大型复杂的项目编译问题.下面这 篇文章我们将用一 ...
- python pip list 命令列出所有安装包和版本信息
c:\Python27\Scripts>pip listDEPRECATION: The default format will switch to columns in the future. ...
- Linux基础命令---service
service service可以控制系统服务(打开.关闭.重启).service在尽可能可预测的环境中运行SystemV init脚本,删除大多数环境变量并将当前工作目录设置为根目录.脚本参数位于“ ...