Codeforces Round #765 Div.1 F. Souvenirs 线段树
题目链接:http://codeforces.com/contest/765/problem/F
题意概述:
给出一个序列,若干组询问,问给出下标区间中两数作差的最小绝对值。
分析:
这个题揭示着数据结构题目世界的真谛......
在线显然凉凉......考虑离线做法。
本题的主要思想:
首先考虑把所有的询问按照右端点排序,用一个指针扫整个序列,同时考虑i作为一组差的右端可以对右端点大于等于i的询问做出的贡献。我们可以发现,我们扫到当前点i,对于所有询问的右端点大于等于i的询问,如果其左端点小于等于i,那么i这个位置就可能对它们的答案做出贡献,换句话说我们只要考虑i作为差的右端可以对哪些左端的答案做出贡献,然后维护当前每个点作为左端的答案,查询的时候直接进行区间最小值的查询即可。
绝对值是麻烦的,因此我们简单一点,考虑所有j<i并且aj>=ai的贡献,然后倒着扫一遍就可以考虑剩下的可能贡献。
假设我们现在扫到位置i,左边有第一个大于ai的元素aj,我们贪心考虑,最终能够让 i作为下标较大的一方参与的答案变得更小 的j'满足:ai<=aj'<aj。但是这个性质显然还不够强,我们继续考虑,发现:
当aj'-ai>aj-aj'时,我们反向扫回来的时候,由于区间[j',j]一定被[j',i]包含,如果存在一个询问包括了[j',i],那么也一定包括了[j',j],显然这个时候aj-aj'是一个更加优秀的答案,aj'-ai更劣。
因此我们找到的j'一定要满足:aj'-ai<=aj-aj' -> 2aj'<=ai+aj,也就是说我们最多找到O(log(ai+a_first_j))个可以对i作为右端点的答案产生贡献的位置。
因为我们将右端点排序,因此我们维护当前所有的点作为下标较小的一方参与的时候的答案,当我们遇到一个询问p的右端点pr=i的时候,只需要查询区间[pl,i]中的最小值即可。
最后倒着来一遍,得到最终的答案。
在log次查找的时候我们实质上找的是权值在[ai,(ai+aj)/2]范围中的小于j的最大下标,分析一下发现可以直接用一棵权值线段树维护,因为我们找的权值区间内的序列下标不可能大于j(不然的话我们在之前就应该找到它了)。
找到第一个j的时候可以直接在序列线段树中进行二分。
时间复杂度O(NlogNloga)
(PS:突然发现变量rank,hash在C++11下面编译不了是什么情况?!)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<set>
#include<map>
#include<vector>
#include<cctype>
#define inf (1e9+5)
using namespace std;
const int MAXN=;
const int MAXM=; int N,M,A[MAXN],Rank[MAXN],B[MAXN],ans[MAXM],tot;
struct data{
int l,r,id;
friend bool operator < (data x,data y){
return x.r<y.r;
}
}q[MAXM];
struct segment_tree{
static const int maxn=;
int rt,np,lc[maxn],rc[maxn],mx[maxn],mn[maxn];
void init(){ rt=np=; }
void pushup1(int now){ mn[now]=min(mn[lc[now]],mn[rc[now]]); }
void pushup2(int now){ mx[now]=max(mx[lc[now]],mx[rc[now]]); }
void build(int &now,int L,int R){
now=++np,lc[now]=rc[now]=,mx[now]=-,mn[now]=inf;
if(L==R) return;
int m=L+R>>;
build(lc[now],L,m);
build(rc[now],m+,R);
}
void update1(int now,int L,int R,int pos,int v){
if(L==R){ mn[now]=min(mn[now],v); return; }
int m=L+R>>;
if(pos<=m) update1(lc[now],L,m,pos,v);
else update1(rc[now],m+,R,pos,v);
pushup1(now);
}
void update2(int now,int L,int R,int pos,int v){
if(L==R){ mx[now]=max(mx[now],v); return; }
int m=L+R>>;
if(pos<=m) update2(lc[now],L,m,pos,v);
else update2(rc[now],m+,R,pos,v);
pushup2(now);
}
int query_p(int now,int L,int R,int v){
if(L==R) return mx[now]>=v?L:-;
int m=L+R>>;
if(mx[rc[now]]>=v) return query_p(rc[now],m+,R,v);
return query_p(lc[now],L,m,v);
}
int query_max(int now,int L,int R,int A,int B){
if(A<=L&&R<=B) return mx[now];
int m=L+R>>;
if(B<=m) return query_max(lc[now],L,m,A,B);
if(A>m) return query_max(rc[now],m+,R,A,B);
return max(query_max(lc[now],L,m,A,B),query_max(rc[now],m+,R,A,B));
}
int query_min(int now,int L,int R,int A,int B){
if(A<=L&&R<=B) return mn[now];
int m=L+R>>;
if(B<=m) return query_min(lc[now],L,m,A,B);
if(A>m) return query_min(rc[now],m+,R,A,B);
return min(query_min(lc[now],L,m,A,B),query_min(rc[now],m+,R,A,B));
}
}st1,st2; void data_in()
{
scanf("%d",&N);
for(int i=;i<=N;i++) scanf("%d",&A[i]);
scanf("%d",&M);
for(int i=;i<=M;i++){
scanf("%d%d",&q[i].l,&q[i].r);
q[i].id=i;
}
}
int id(int v){ return upper_bound(B+,B+tot+,v)-B-; }
void solve()
{
st1.init(); st2.init();
st1.build(st1.rt,,N); st2.build(st2.rt,,tot);
int p=;
st1.update2(st1.rt,,N,,A[]);
st2.update2(st2.rt,,tot,Rank[],);
for(int i=;i<=N;i++){
int j=st1.query_p(st1.rt,,N,A[i]);
if(j!=-){
st1.update1(st1.rt,,N,j,A[j]-A[i]);
while((j=st2.query_max(st2.rt,,tot,Rank[i],id((A[i]+A[j])/)))!=-){
st1.update1(st1.rt,,N,j,A[j]-A[i]);
if(A[j]-A[i]==) break;
}
}
while(p<=M&&q[p].r<=i){
ans[q[p].id]=min(ans[q[p].id],st1.query_min(st1.rt,,N,q[p].l,q[p].r));
p++;
}
if(p>M) break;
st1.update2(st1.rt,,N,i,A[i]);
st2.update2(st2.rt,,tot,Rank[i],i);
}
}
void work()
{
memcpy(B,A,sizeof(A));
sort(B+,B+N+);
tot=unique(B+,B+N+)-B-; for(int i=;i<=N;i++) Rank[i]=lower_bound(B+,B+tot+,A[i])-B;
for(int i=;i<=M;i++) ans[i]=inf;
sort(q+,q+M+);
solve(); int l=,r=N;
while(l<r) swap(Rank[l],Rank[r]),swap(A[l++],A[r--]);
for(int i=;i<=M;i++){
swap(q[i].l,q[i].r);
q[i].l=N-q[i].l+,q[i].r=N-q[i].r+;
}
sort(q+,q+M+);
solve(); for(int i=;i<=M;i++) printf("%d\n",ans);
}
int main()
{
data_in();
work();
return ;
}
Codeforces Round #765 Div.1 F. Souvenirs 线段树的更多相关文章
- Codeforces Codeforces Round #316 (Div. 2) C. Replacement 线段树
C. ReplacementTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/570/problem ...
- Codeforces Round #603 (Div. 2) E. Editor 线段树
E. Editor The development of a text editor is a hard problem. You need to implement an extra module ...
- Codeforces Round #406 (Div. 1) B. Legacy 线段树建图跑最短路
B. Legacy 题目连接: http://codeforces.com/contest/786/problem/B Description Rick and his co-workers have ...
- 【转】Codeforces Round #406 (Div. 1) B. Legacy 线段树建图&&最短路
B. Legacy 题目连接: http://codeforces.com/contest/786/problem/B Description Rick and his co-workers have ...
- Codeforces Round #406 (Div. 2) D. Legacy 线段树建模+最短路
D. Legacy time limit per test 2 seconds memory limit per test 256 megabytes input standard input out ...
- Codeforces Round #278 (Div. 1) Strip (线段树 二分 RMQ DP)
Strip time limit per test 1 second memory limit per test 256 megabytes input standard input output s ...
- Codeforces Round #271 (Div. 2) E. Pillars 线段树优化dp
E. Pillars time limit per test 1 second memory limit per test 256 megabytes input standard input out ...
- Codeforces Round #278 (Div. 2) D. Strip 线段树优化dp
D. Strip time limit per test 1 second memory limit per test 256 megabytes input standard input outpu ...
- Codeforces Round #485 (Div. 2) F. AND Graph
Codeforces Round #485 (Div. 2) F. AND Graph 题目连接: http://codeforces.com/contest/987/problem/F Descri ...
随机推荐
- Python中模块
模块 模块对我来说是什么 模块对我来说,感觉就像亲属或者朋友已经走过的路,他们已经趟过的浑水.掉过的坑.践行过的路线,全部提供给你,在你需要的时候请求帮助,借鉴他们的解决方法一样.都是为了方便走好人生 ...
- python的requests模块爬取网页内容
注意:处理需要用户名密码认证的网站,需要auth字段. # -*- coding:utf-8 -*- import requests headers = { "User-Agent" ...
- 微信小程序实现转义换行符
在html中可以直接使用<br />换行,但是小程序wxml中使用<br />无效,可以换成\n Page({ data: { title: '至少5个字\n请多说些感受吧' ...
- spring boot2整合dubbox全注解
前题 dubbox是dubbo的一个升级版,简单说就是本来dubbo是阿里开发的,现在阿里不维护了,当当网拿过去继续开发.本来阿里的dubbo维护到2.6版本,而再高版本的都是当当网维护的就叫成dub ...
- 面试被问到SPI总结
SPI驱动框架 枚举过程 drivers/spi/spi.c: spi_register_board_info /* 对于每一个spi_master,调用spi_match_master_to_boa ...
- Linux Shell中管道的原理及C实现框架
在shell中我们经常用到管道,有没考虑过Shell是怎么实现管道的呢? cat minicom.log | grep "error" 标准输入.标准输出与管道 我们知道,每一个进 ...
- 20155307 《Java程序设计》课堂实践项目MyOD
一开始没理解老师的要求,交的截图是错误的. import java.io.FileInputStream; import java.io.IOException; import java.io.Inp ...
- sql语句-3-聚合数据查询
- yaml中的锚点和引用
项目引入yaml语言来写配置文件,最近发现利用其锚点&和引用*的功能,可以极大减少配置文件中的重复内容,将相同配置内容收敛到锚点处,修改时,只需要修改锚点处的内容,即可在所有引用处生效. ya ...
- 新技能get,使用PHPStorm的deployment工具
1. 工具栏 Tools - Deployment - Configuration 2. 添加一个服务端的配置信息 type 类型可以选择:FTP.local等. 填完信息别忘了点"Test ...