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到了异 ...
随机推荐
- 十天精通CSS3(10)
多列布局——Columns 为了能在Web页面中方便实现类似报纸.杂志那种多列排版的布局,W3C特意给CSS3增加了一个多列布局模块(CSS Multi Column Layout Module).它 ...
- Civil and Evil Engineer(普林姆)
http://acm.sdut.edu.cn:8080/vjudge/contest/view.action?cid=198#problem/E 水题一道,题意就是让求一遍最小生成树与最大生成树,但我 ...
- 主成分分析(PCA)算法,K-L变换 角度
主成分分析(PCA)是多元统计分析中用来分析数据的一种方法,它是用一种较少数 量的特征对样本进行描述以达到降低特征空间维数的方法,它的本质实际上是K-L变换.PCA方法最著名的应用应该是在人脸识别中特 ...
- soapUI-DataGen
1.1.1 DataGen 1.1.1.1 概述 – DataGen DataGen TestStep可用于生成要用作TestCases中的输入的数据,例如数字或日期序列,随机选择等.生成的数据可作 ...
- curl命令总结
curl常用命令http://www.cnblogs.com/gbyukg/p/3326825.html curl命令后面的网址需要用双引号括起来,原因:防止有特殊字符 &号就是特殊字符 cu ...
- ServiceStack DotNet Core前期准备
下载DotNet Core SDK 下载地址:https://dotnet.microsoft.com/download. 安装完成之后通过cmd的命令行进行确认. 官方自带的cmd比较简陋,可以用c ...
- 绘制loss曲线
第一步保存日志文件,用重定向即可: $TOOLS/caffe train --solver=$SOLVERFILE >& |tee out.log 第二步直接绘制: python plo ...
- python 读写压缩文件
gzip 和bz2 模块可以很容易的处理这些文件.两个模块都为open() 函数提供了另外的实现来解决这个问题.比如,为了以文本形式读取压缩文件,可以这样做: # gzip compression i ...
- 数据仓库原理<4>:联机分析处理(OLAP)
本文转载自:http://www.cnblogs.com/hbsygfz/p/4762085.html 1. 引言 本篇主要介绍数据仓库中的一项重要分析技术——联系分析处理(OLAP). 在第一篇笔者 ...
- Linux基础命令---zip
zip zip是一种最通用的文件压缩方式,使用于unix.msdos.windows.OS等系统.如果在编译zip时包含bzip 2库,zip现在也支持bzip 2压缩.当将大于4GB的文件添加到存档 ...