题目链接

题意:给定一个长度为n的数组与m个查询。第i个查询要求输出数组下标区间[li,ri]内的数之间的距离(差的绝对值)的最小值。

分析:离线处理查询。将查询区间按右端点从小到大排序,维护一个数据结构,使得将数组元素a1,a2,...,ai插入到数据结构之后能够快速查询以ai为右端点的查询区间的答案。考虑ai对查询区间的贡献,设d=|ai-aj|(j<i),则对于满足l≤j,r=a[i]的查询区间[l,r],有查询区间[l,r]的答案≤d。因此可以用线段树来维护答案,线段树每个结点记录左端点处于对应范围内时(当右端点 为ai时)的查询区间的上确界。

若暴力处理ai对查询区间的贡献,则时间复杂度为O(n),这显然是不可接受的。不妨先设a1,a2,...,ai-1均大于等于ai(一般情况下处理2次即可),则在计算完元素对(ai,ai-1)对查询区间的贡献后,设下一个选取的元素对为(ai,aj),则aj应满足aj≤(ai+ai-1)/2。这是因为:1.aj≥ai-1时元素对(ai,aj)不优于元素对(ai,ai-1)的贡献;2.(ai+ai-1)/2≤aj≤ai-1时元素对(ai,aj)的贡献不优于元素对(ai-1,aj)的贡献。依次类推,计算ai对查询区间的贡献时间复杂度可以优化到O(lgn)。

下面讨论程序的实现。我们需要一个数据结构,使得能够快速求出数组下标在[1,j-1]范围内大小在范围[ai,(ai+aj)/2]内的下标最大的数。可以建一棵线段树,线段树的每个结点[l,r]存一个vector,vector里将al,al+1,...,ar按从小到大排序,然后就可以O(lgn^2)地完成这件事(官方题解似乎有O(lgn)的做法)。

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6+10;
struct que
{int l,r,i;bool operator < (const que &o) const{return r<o.r;}
}qu[maxn];
int n,m,a[maxn],ans[maxn];
vector<int> vec[maxn*4];
int minv[maxn*4],ql,qr,p,val;
void build(int o,int l,int r)
{if (l==r) {vec[o].push_back(a[l]);return ;}int mid=(l+r)/2;build(2*o,l,mid);build(2*o+1,mid+1,r);int i=0,j=0;while (i<vec[2*o].size()&&j<vec[2*o+1].size()){if (vec[2*o][i]<=vec[2*o+1][j]) vec[o].push_back(vec[2*o][i]),i++;else vec[o].push_back(vec[2*o+1][j]),j++;}while (i<vec[2*o].size()) vec[o].push_back(vec[2*o][i]),i++;while (j<vec[2*o+1].size()) vec[o].push_back(vec[2*o+1][j]),j++;
}
int find(int o,int l,int r,int mine,int maxe)
{if (ql<=l&&r<=qr){vector<int>::iterator it=lower_bound(vec[o].begin(),vec[o].end(),mine);if (it==vec[o].end()||*it>maxe) return -1;if (l==r) return l;int mid=(l+r)/2,ret=find(2*o+1,mid+1,r,mine,maxe);if (ret!=-1) return ret;return find(2*o,l,mid,mine,maxe);}int mid=(l+r)/2,ret=-1;if (qr>mid) ret=find(2*o+1,mid+1,r,mine,maxe);if (ret!=-1) return ret;return find(2*o,l,mid,mine,maxe);
}
void updata(int o,int l,int r)
{if (l==r) {minv[o]=min(minv[o],val);return ;}int mid=(l+r)/2;if (p<=mid) updata(2*o,l,mid);else updata(2*o+1,mid+1,r);minv[o]=min(minv[2*o],minv[2*o+1]);
}
int query(int o,int l,int r)
{if (ql<=l&&r<=qr) return minv[o];int mid=(l+r)/2,ret=1e9;if (ql<=mid) ret=min(ret,query(2*o,l,mid));if (qr>mid) ret=min(ret,query(2*o+1,mid+1,r));return ret;
}
int main()
{cin>>n;for (int i=1;i<=n;i++) scanf("%d",&a[i]);build(1,1,n);cin>>m;for (int i=1;i<=m;i++) scanf("%d%d",&qu[i].l,&qu[i].r),qu[i].i=i;sort(qu+1,qu+m+1);for (int i=0;i<maxn*4;i++) minv[i]=1e9;int pos=1;for (int i=2;i<=n;i++){int j;ql=1;qr=i-1;j=find(1,1,n,a[i],1e9);while (j!=-1){int d=a[j]-a[i];p=j;val=d;updata(1,1,n);if (!d||j==1) break;d/=2;ql=1;qr=j-1;j=find(1,1,n,a[i],a[i]+d);}ql=1;qr=i-1;j=find(1,1,n,0,a[i]);while (j!=-1){int d=a[i]-a[j];p=j;val=d;updata(1,1,n);if (!d||j==1) break;d/=2;ql=1;qr=j-1;j=find(1,1,n,a[i]-d,a[i]);}while (pos<=m&&qu[pos].r==i){ql=qu[pos].l;qr=i;ans[qu[pos].i]=query(1,1,n);pos++;}}for (int i=1;i<=m;i++) printf("%d\n",ans[i]);return 0;
}

【题解】codeforces765F Souvenirs相关推荐

  1. Codeforces765F. Souvenirs

    $n \leq 100000$的数列给$m \leq 300000$的询问,每次问一个区间里选两个数差的最小值.数字$\leq 1e9$. 根号算法: 无脑莫队加个平衡树或者权值线段树来查前驱后继是$ ...

  2. codeforces765F Souvenirs

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

  3. codeforces Round 21 808E. Selling Souvenirs 【dp好题】

    codeforces Round 21 808E. Selling Souvenirs [dp好题] E. Selling Souvenirs time limit per test 2 second ...

  4. [JS][dfs]题解 | #迷宫问题#

    题解 | #迷宫问题# 题目链接 迷宫问题 题目描述 定义一个二维数组 N*M ,如 5 × 5 数组下所示: int maze[5][5] = { 0, 1, 0, 0, 0, 0, 1, 1, 1 ...

  5. [JS][dp]题解 | #打家劫舍(一)#

    题解 | #打家劫舍(一)# 题目链接 打家劫舍(一) 题目描述 描述 你是一个经验丰富的小偷,准备偷沿街的一排房间,每个房间都存有一定的现金,为了防止被发现,你不能偷相邻的两家,即,如果偷了第一家, ...

  6. [JS]题解 | #魔法数字#

    题解 | #魔法数字# 题目链接 魔法数字 题目描述 牛妹给牛牛写了一个数字n,然后又给自己写了一个数字m,她希望牛牛能执行最少的操作将他的数字转化成自己的. 操作共有三种,如下: 在当前数字的基础上 ...

  7. [JS]题解 | #岛屿数量#

    题解 | #岛屿数量# 题目链接 岛屿数量 题目描述 时间限制:1秒 空间限制:256M 描述 给一个01矩阵,1代表是陆地,0代表海洋, 如果两个1相邻,那么这两个1属于同一个岛.我们只考虑上下左右 ...

  8. [JS] 题解:提取不重复的整数

    题解:提取不重复的整数 https://www.nowcoder.com/practice/253986e66d114d378ae8de2e6c4577c1 时间限制:1秒 空间限制:32M 描述 输 ...

  9. 洛谷-题解 P2672 【推销员】

    独门思路!链表加优先队列! 这题一望,贪心是跑不掉了,但是我贪心并不好,所以想到了一个复杂一些但思路更保稳的做法 思路: 1 因为是离线操作,所以我们可以倒着求,先求x=n的情况,因为那样直接就知道了 ...

最新文章

  1. Ansible-playbook简单应用的几个实例
  2. 前端学习(3181):ant-design的button介绍
  3. vue 保留小数点厚一位_2019黑龙江公务员考试行测资料分析:保留有效数字巧解对位数相乘...
  4. 今日头条把微信按在地上摩擦
  5. 剑指offer面试题47. 礼物的最大价值(动态规划)
  6. 切换账号_微软 Edge 更新:自动切换工作 / 生活账号,移动端上线集锦功能
  7. (七)数字后端之形式验证
  8. layui树形美化_Layui导航树美化 - walkwithdream的个人空间 - OSCHINA - 中文开源技术交流社区...
  9. iOS苹果超级签苹果分发平台企鹅:422903005
  10. 深入探讨为什么hbase读数据(scan)性能低
  11. TCP IP协议之初识
  12. fault tolerance中的错误和故障检测(Error and Fault Detection Mechanisms)
  13. 用pygame为大家燃放新年烟花
  14. vue+node.js+mysql的数据库课程设计有感
  15. 为什么辞职(或裸辞)之后很难再找到工作,而且能力越高越明显?
  16. elementUI Form中 勾选框设置必选不提示问题
  17. 成熟血氧仪方案--【医疗电子】
  18. 怎样在计算机里恢复云文档图标,电脑常识科普:Win10资源管理器中的WPS云文档图标怎么彻底删除...
  19. 国家lpv9服务器包括哪些项目,ipv6与ipv9什么关系
  20. MySQL按时间段随机更新时间

热门文章

  1. VR用到教育上了?90后怎么就没有赶上呢!
  2. 机器学习:鸢尾花(Iris)分类
  3. 会议及作用篇--项目管理(三)
  4. RC低通滤波原理(笔记)
  5. 有什么比较好用的视频录像软件
  6. Downloading NEX-GDDP data from google Earth Engine
  7. 正负样本的分配atss
  8. 天源财富:突破“极限”!我科学家发现迄今最高能量光子
  9. JSP入门教程(二)
  10. java se包括哪些_Java SE