题解-TIOJ1905 最理想的身高差
Problem
题目大意:求区间最小差值
序列长度\(1e5\),询问\(2e5\)
Solution
总体思路就是找出所有可能作为答案的点对,用资料结构_(:зゝ∠)_维护,然后询问
至于如何找出所有可能作为答案的点对,我们先考虑左边比右边小的点对,考虑枚举点对左端点,那么可能作为答案的右端点一定是递减的
其次,若当前左端点为\(l\),值为\(x\),从左至右的右端点\(r\)的值依次为\(\{v_1,v_2,\cdots ,v_k\}\),则一定存在\(\frac 12(x+v_i)> v_{i+1}\),因为如果\(\frac 12(x+v_i)\leq v_{i+1}\),则在区间\([l,r_{i+1}]\)中,点对\((l,r_i)\)或\((r_i,r_{i+1})\)一定会更优
所以对于一个固定的左端点,\(v_i-x\)每次会折半,所以右端点的数量不超过\(log_2(10^9)\approx 30\)个
对于左边比右边大的点对处理也如法炮制,即对于整个区间来说,可能作为答案的点对数量不超过\(60n\)
如何快速查找在区间\([r_i,n]\)中数值范围在\([x,\frac 12(x+r_i)]\)中的最靠左的点呢
考虑对所有点权离散化后对点权建主席树,在每棵线段树中维护的是位置集合,即如果要查找上面的东西,就只要在第\(x\)棵主席树到第\(\frac 12(x+r_i)\)棵主席树间查找区间\([r_i,n]\)的最左边非零节点
我们成功找到了所有可能为答案的点对,现在来回答询问
对序列维护一棵线段树,考虑将所有点对包括询问按照右端点排序,从左往右枚举右端点,如果是答案点对则在线段树中修改点对左端点的值,如果是询问,则查询区间\([l,r]\)的最小值
预处理复杂度\(O(n\log_2^2n)\),询问复杂度\(O((n\log n+m)\log n)\)
总体复杂度\(O(n\log_2^2n+m\log n)\),其中一个\(\log\)基本跑不满,时限也开到了\(6s\),实测一个点最慢\(1.3s\),所以不用担心常数问题
tips:
- 预处理中可以不用主席树,改用枚举右端点可以使用单调栈加线段树
- 最后如果用主席树维护的话可以在线询问
- 有一个\(O((n+m)\sqrt n)\)的分块做法,但常数很大,实测一个点最慢\(5s\)
况且这里地方太小,写不下
Code
代码又臭又长,如果不想写这么长,逆序后线段树直接玩即可
#include<bits/stdc++.h>
using namespace std;
#define rg register
template <typename _Tp> inline _Tp read(_Tp&x){
char c11=getchar();x=0;
while(!isdigit(c11))c11=getchar();
while(isdigit(c11))x=x*10+c11-'0',c11=getchar();
return x;
}
template <typename _Tp> inline void cmax(_Tp&A,_Tp B) {A=(A>B?A:B);}
template <typename _Tp> inline void cmin(_Tp&A,_Tp B) {A=(A<B?A:B);}
const int N=101000,M=1001000,ae=18;
struct Edge{int v,nxt,w;}a[N*ae+M];
int head[N],Head[N];
int v[N],b[N],Ans[M];
int n,m,_;
inline void add(int u,int v,int w){a[++_].v=v,a[_].w=w,a[_].nxt=head[u],head[u]=_;}
inline void Add(int u,int v,int w){a[++_].v=v,a[_].w=w,a[_].nxt=Head[u],Head[u]=_;}
struct tmp_{
int ps,vl;
friend inline int operator < (const tmp_&A,const tmp_&B) {return A.vl<B.vl;}
}tnd[N];
struct node{int l,r,v;}seg[N*ae];
int rt[N],cnt=0;
inline void Update(int l,int r,int&x,int ps){
seg[++cnt]=seg[x];x=cnt,++seg[x].v;
if(l==r)return ;int mid(l+r>>1);
if(ps<=mid)Update(l,mid,seg[x].l,ps);
else Update(mid+1,r,seg[x].r,ps);
return ;
}
inline int Query(int l,int r,int x1,int x2,int L,int R){
if(seg[x2].v-seg[x1].v==0)return 0;
if(l==r)return l;int mid(l+r>>1),tmp;
if(L<=l&&r<=R){
int t=seg[seg[x2].l].v-seg[seg[x1].l].v;
if(t)return Query(l,mid,seg[x1].l,seg[x2].l,L,R);
else return Query(mid+1,r,seg[x1].r,seg[x2].r,L,R);
}
if(L<=mid)if(tmp=Query(l,mid,seg[x1].l,seg[x2].l,L,R))return tmp;
if(mid<R)if(tmp=Query(mid+1,r,seg[x1].r,seg[x2].r,L,R))return tmp;
return 0;
}
int val[N<<2];
inline void build(int l,int r,int x){
val[x]=0x3f3f3f3f;
if(l==r)return ;int mid(l+r>>1);
build(l,mid,x<<1);build(mid+1,r,x<<1|1);
}
inline void update(int l,int r,int x,int ps,int alpha){
cmin(val[x],alpha);
if(l==r)return ;
int mid(l+r>>1);
if(ps<=mid)update(l,mid,x<<1,ps,alpha);
else update(mid+1,r,x<<1|1,ps,alpha);
}
inline int query(int l,int r,int x,int L,int R){
if(L<=l&&r<=R)return val[x];
int mid(l+r>>1),res(0x3f3f3f3f);
if(L<=mid)cmin(res,query(l,mid,x<<1,L,R));
if(mid<R)cmin(res,query(mid+1,r,x<<1|1,L,R));
return res;
}
int dl;
void init();void mainwork();
void print();void prework();
int main(){
init();
prework();
mainwork();
print();
return 0;
}
void mainwork(){
read(m);
for(rg int i=1,x,y;i<=m;++i){
read(x),read(y);
Add(y,x,i);
}
build(1,n,1);
for(rg int x=1;x<=n;++x){
for(rg int i=head[x];i;i=a[i].nxt)
update(1,n,1,a[i].v,a[i].w);
for(rg int i=Head[x];i;i=a[i].nxt)
Ans[a[i].w]=query(1,n,1,a[i].v,x);
}return ;
}
void prework(){
for(rg int i=1;i<=n;++i)tnd[i].ps=i,tnd[i].vl=v[i];
sort(tnd+1,tnd+n+1);
for(rg int i=1;i<=n;++i){
if(!rt[tnd[i].vl])rt[tnd[i].vl]=rt[tnd[i].vl-1];
Update(1,n,rt[tnd[i].vl],tnd[i].ps);
}
int las,l,r;
for(rg int i=1;i^n;++i){
las=i;
while(las){
l=v[i]-1;
r=las==i?dl:lower_bound(b+1,b+dl+1,b[v[i]]+b[v[las]]>>1)-b;
if(las^i&&(b[r]<<1)>=b[v[i]]+b[v[las]])--r;if(l>r)break;
las=Query(1,n,rt[l],rt[r],las+1,n);
if(las)add(las,i,b[v[las]]-b[v[i]]);
}
}
for(rg int i=1;i^n;++i){
las=i;
while(las){
r=v[i];
l=las==i?1:lower_bound(b+1,b+dl+1,b[v[i]]+b[v[las]]>>1)-b;
if(las^i&&(b[l]<<1)<=b[v[i]]+b[v[las]])++l;if(l>r)break;
las=Query(1,n,rt[l-1],rt[r-1],las+1,n);
if(las)add(las,i,b[v[i]]-b[v[las]]);
}
}
return ;
}
void init(){
read(n);
for(rg int i=1;i<=n;++i)b[i]=read(v[i]);
sort(b+1,b+n+1);dl=unique(b+1,b+n+1)-b-1;
for(rg int i=1;i<=n;++i)v[i]=lower_bound(b+1,b+dl+1,v[i])-b;
return ;
}
void print(){
for(rg int i=1;i<=m;++i)
printf("%d\n",Ans[i]);
return ;
}
题解-TIOJ1905 最理想的身高差的更多相关文章
- Pie(求最小身高差,dp)
Pie Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) Total Submis ...
- L1-040 最佳情侣身高差
专家通过多组情侣研究数据发现,最佳的情侣身高差遵循着一个公式:(女方的身高)×1.09 =(男方的身高).如果符合,你俩的身高差不管是牵手.拥抱.接吻,都是最和谐的差度. 下面就请你写个程序,为任意一 ...
- 北京师范大学第十六届程序设计竞赛决赛 C萌萌哒身高差
链接:https://www.nowcoder.com/acm/contest/117/C来源:牛客网 萌萌哒身高差 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K,其他 ...
- 团体程序设计天梯赛-练习集-L1-040. 最佳情侣身高差
L1-040. 最佳情侣身高差 专家通过多组情侣研究数据发现,最佳的情侣身高差遵循着一个公式:(女方的身高)×1.09=(男方的身高).如果符合,你俩的身高差不管是牵手.拥抱.接吻,都是最和谐的差度. ...
- bnuoj-53073 萌萌哒身高差 【数学】【非原创】
"清明时节雨纷纷,路上行人欲断魂." 然而wfy同学的心情是愉快的,因为BNU ACM队出去春游啦!并且,嗯... 以下是wfy同学的日记: 昨天,何老师告诉我们:明天我们去春游, ...
- PAT 天梯赛 L1-040. 最佳情侣身高差 【水】
题目链接 https://www.patest.cn/contests/gplt/L1-040 AC代码 #include <iostream> #include <cstdio&g ...
- Codeforces Round div2 #541 题解
codeforces Round #541 abstract: I构造题可能代码简单证明很难 II拓扑排序 III并查集 启发式排序,带链表 IV dp 处理字符串递推问题 V 数据结构巧用:于二叉树 ...
- PTA|团体程序设计天梯赛-练习题目题解锦集(C/C++)(持续更新中……)
PTA|团体程序设计天梯赛-练习题目题解锦集(持续更新中) 实现语言:C/C++: 欢迎各位看官交流讨论.指导题解错误:或者分享更快的方法!! 题目链接:https://pintia.cn/ ...
- RMQ——[USACO Jan07] 均衡队形题解
题目:[USACO Jan07] 均衡队形 描述: 题目描述 农夫约翰的 N (1 ≤ N ≤ 50,000) 头奶牛,每天挤奶时总会按同样的顺序站好.一日,农夫约翰决定为奶牛们举行一个“终极飞盘”比 ...
随机推荐
- 设计模式---行为变化模式之命令模式(Command)
前提:行为变化模式 在组件的构建过程中,组建行为的变化经常导致组件本身剧烈的变化.“行为变化”模式将组件的行为和组件本身进行解耦,从而支持组件的变化,实现两者之间的松耦合. 类中非虚函数和静态函数方法 ...
- HTML5-语义化标签
article -- 解释 article标签装载显示一个独立的文章内容.例如一篇完整的论坛帖子,一则网站新闻,一篇博客文章等等,一个用户评论等等 artilce可以嵌套,则内层的artilce对外层 ...
- ContentType组件
django提供的一个快速连表操作的组件 适用于:一个字段确定不了唯一: 如:pricepolicy表中,course_id和content_type中对应的课程类型id才能确定唯一: model.p ...
- 【leetcode-66】 加一
给定一个由整数组成的非空数组所表示的非负整数,在该数的基础上加一. 最高位数字存放在数组的首位, 数组中每个元素只存储一个数字. 你可以假设除了整数 0 之外,这个整数不会以零开头. 示例 1: 输入 ...
- springboot单元测试 注入失败 空指针
今天写代码,在test的类中@Autowired注入要测试的@Component类,但发现一运行就会报空指针异常java.lang.NullPointException,但发现使用new的方法的时候可 ...
- 解决 git push Failed to connect to 127.0.0.1 port 8-87: 拒绝连接
今天在本地使用nsq 测试的时候总是提示端口被占用 通过查看环境变量确实存在该代理 如何解决 使用netstat 命令查看端口被占用情况 根据经常ID号查看是哪一个进程正在被占用 如何还是不行,则在[ ...
- 自学python 1.
1.变量命名规范 1.数字,字母,下划线 2.不能数字开头和纯数字 3.要有意义 4.不要太长 5.驼峰和下划线 6.不要用中文 7.不能用关键字 8.区分大小写2.name = input(&quo ...
- Spring 单例模式
恶汉模式:Ehan.java package com.cn.danli; /** * 饿汉式单例模式 */ public class Ehan { private static Ehan eh = n ...
- Devexpress GridControl切换数据源
gridControl1.DataSource = dt1; (gridControl1.DefaultView as GridView).Columns.Clear();//切换前需要先把列清空了. ...
- luogu 3045 优先队列反悔/bzoj 2590
N头奶牛,价格Pi,K张优惠券,优惠券购买降为Ci,不超过M的钱最多可买多少奶牛 先将c值k小的加入,将它们省下的钱加入优先队列(省下的钱由少到多),在将k+1-n用p排序,再逐个与优先队列中弹出的比 ...