CF765F Souvenirs

题意翻译

给出\(n(2 \le n \le 10^5 )\) ,一个长为\(n\)的序列\(a(0 \le a_i \le 10^9 )\)。

给出\(m(1\le m \le 2*10^5 )\),接下来\(m\)组询问。

每组询问给出一个\(l,r(1\le l < r\le n )\),代表询问最小的\(|a_i-a_j|\) 的值(\(l\le i <j\le r\) ,\(a_i\) 可以等于\(a_j\) )


蒟蒻\(\tt{Dew}\)又双叒叕花大几个小时去弄懂这个题,而直到现在,我也只是明白了这个题为什么可以这么做,却不是太明白这种题如何去想。


首先可以看出这个题说不定可以莫队套平衡树卡过去,没什么别的想法还是写写吧,估计比暴力还是强一些的。

然后考虑一些思考的出发点,比如

  • 值域?二分值域?划分修改?
  • 移动询问的指针?
  • 把询问给线段树分治掉?
  • 单调性?

不妨先考虑一些简单的暴力,比如说,我们把询问按右指针排序,然后开始处理它们。

若当前处理到的位置为\(r\),我们对\(r\)前面的位置\(i\)维护答案数组\(ans_i\),代表区间\([i,r]\)的答案,每次移动右指针时,我们暴力更新每个位置的答案。

考虑修补这个暴力。

  • 发现询问\(ans_i\)也可以看做询问\(\min_{i\le k <r} ans_k\),这启发我们去区间查询,然后每次移动时不修改所有的值,选择线段树进行维护。
  • 具体的,在线段树上点代表的区间上,存下这个区间所有的\(a_i\),然后在这个区间上二分就能够更新这个区间的答案了。
  • 然后发现复杂度更高了,按道理有些值是不需要修改的,哪些值呢?
  • 发现\(ans_i\)数组是单调不升的。如果我们成功修改了位置靠右的某个值,并设当前的答案为\(mi\)(注意这个是包含原本节点的答案的最小值),那么在一个某个在\(Ta\)左边的节点上贡献的答案不如\(mi\)时,我们就没有必要进入这个节点的子节点了。
  • 这样做的复杂度单次操作是\(\log n \log Maxa_i\)的,原因其实很简单,每次成功贡献答案后答案必定减半。为什么?如果\(r\)对\(j\)的答案为\(mi_j\),\(r\)对\(i\)的答案为\(mi_i\),为了避免\(i\)直接把\(j\)给更新掉,一定有\(mi_i< \frac{mi_j}{2}\)

总结:积累做题经验,多开脑洞..


Code:

#include <cstdio>
#include <algorithm>
#include <vector>
const int N=1e5+10;
struct node
{
int i,l,r;
bool friend operator <(node n1,node n2){return n1.r<n2.r;}
}q[N<<2];
int ans[N<<2],Ans[N<<2],n,m,a[N],mi;
std::vector <int> seg[N<<2];
int min(int x,int y){return x<y?x:y;}
#define ls id<<1
#define rs id<<1|1
const int inf=0x3f3f3f3f;
void build(int id,int l,int r)
{
for(int i=l;i<=r;i++) seg[id].push_back(a[i]);
std::sort(seg[id].begin(),seg[id].end());
ans[id]=inf;
if(l==r) return;
int mid=l+r>>1;
build(ls,l,mid),build(rs,mid+1,r);
}
void change(int id,int l,int r,int p,int x)
{
if(r<=p)
{
std::vector <int>::iterator it=std::upper_bound(seg[id].begin(),seg[id].end(),x);
if(it!=seg[id].end()) ans[id]=min(ans[id],*it-x);
if(it!=seg[id].begin()) ans[id]=min(ans[id],x-*(it-1));
if(mi<=ans[id]) return;//右边已经有比Ta优秀的了
if(l==r){mi=min(mi,ans[id]);return;}
}
int mid=l+r>>1;
if(p>mid) change(rs,mid+1,r,p,x);//注意先走右边
change(ls,l,mid,p,x);
ans[id]=min(ans[id],min(ans[ls],ans[rs]));
mi=min(mi,ans[id]);//最后更新Ta
}
int query(int id,int L,int R,int l,int r)
{
if(L==l&&R==r) return ans[id];
int Mid=L+R>>1;
if(r<=Mid) return query(ls,L,Mid,l,r);
else if(l>Mid) return query(rs,Mid+1,R,l,r);
else return min(query(ls,L,Mid,l,Mid),query(rs,Mid+1,R,Mid+1,r));
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",a+i);
build(1,1,n);
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d",&q[i].l,&q[i].r);
q[i].i=i;
}
std::sort(q+1,q+1+m);
for(int p=1,i=2;i<=n;i++)
{
mi=inf;
change(1,1,n,i-1,a[i]);
for(;p<=m&&q[p].r<=i;++p)
Ans[q[p].i]=query(1,1,n,q[p].l,i);
}
for(int i=1;i<=m;i++)
printf("%d\n",Ans[i]);
return 0;
}

2018.11.29

CF765F Souvenirs 解题报告的更多相关文章

  1. CH Round #56 - 国庆节欢乐赛解题报告

    最近CH上的比赛很多,在此会全部写出解题报告,与大家交流一下解题方法与技巧. T1 魔幻森林 描述 Cortana来到了一片魔幻森林,这片森林可以被视作一个N*M的矩阵,矩阵中的每个位置上都长着一棵树 ...

  2. 二模13day1解题报告

    二模13day1解题报告 T1.发射站(station) N个发射站,每个发射站有高度hi,发射信号强度vi,每个发射站的信号只会被左和右第一个比他高的收到.现在求收到信号最强的发射站. 我用了时间复 ...

  3. BZOJ 1051 最受欢迎的牛 解题报告

    题目直接摆在这里! 1051: [HAOI2006]受欢迎的牛 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 4438  Solved: 2353[S ...

  4. 习题:codevs 2822 爱在心中 解题报告

    这次的解题报告是有关tarjan算法的一道思维量比较大的题目(真的是原创文章,希望管理员不要再把文章移出首页). 这道题蒟蒻以前做过,但是今天由于要复习tarjan算法,于是就看到codevs分类强联 ...

  5. 习题:codevs 1035 火车停留解题报告

    本蒟蒻又来写解题报告了.这次的题目是codevs 1035 火车停留. 题目大意就是给m个火车的到达时间.停留时间和车载货物的价值,车站有n个车道,而火车停留一次车站就会从车载货物价值中获得1%的利润 ...

  6. 习题: codevs 2492 上帝造题的七分钟2 解题报告

    这道题是受到大犇MagHSK的启发我才得以想出来的,蒟蒻觉得自己的代码跟MagHSK大犇的代码完全比不上,所以这里蒟蒻就套用了MagHSK大犇的代码(大家可以关注下我的博客,友情链接就是大犇MagHS ...

  7. 习题:codevs 1519 过路费 解题报告

    今天拿了这道题目练练手,感觉自己代码能力又增强了不少: 我的思路跟别人可能不一样. 首先我们很容易就能看出,我们需要的边就是最小生成树算法kruskal算法求出来的边,其余的边都可以删掉,于是就有了这 ...

  8. NOIP2016提高组解题报告

    NOIP2016提高组解题报告 更正:NOIP day1 T2天天爱跑步 解题思路见代码. NOIP2016代码整合

  9. LeetCode 解题报告索引

    最近在准备找工作的算法题,刷刷LeetCode,以下是我的解题报告索引,每一题几乎都有详细的说明,供各位码农参考.根据我自己做的进度持续更新中......                        ...

随机推荐

  1. Hibernate三种状态的区分,以及save,update,saveOrUpdate,merge等的使用

    Hibernate的对象有3种状态,分别为:瞬时态(Transient). 持久态(Persistent).脱管态(Detached).处于持久态的对象也称为PO(Persistence Object ...

  2. C++从静态对象的初始化顺序理解static关键字

    问题 首先考虑一个全局变量的初始化顺序问题 在头文件1中: extern int b; ; 在头文件2中: extern int a; ; 源文件中包含了头文件1和头文件2,这种情况下a和b可能的值是 ...

  3. LUIS 语义识别API调用方法

    本例使用itchat获取微信文字消息,发送给LUIS返回识别消息,再将返回消息格式化后通过微信发回 关于itchat的使用参考我的另外一篇随笔itchat个人练习 语音与文本图灵测试例程 # -*- ...

  4. DataRow的RowState属性变化

    DataRow的RowState属性(状态)取值有5种:Detached, Unchanged, Added, Deleted, Modified. 当我们用DataRow newRow = Data ...

  5. angular之$broadcast、$emit、$on传值

    文件层级 index.html <!DOCTYPE html> <html ng-app="nickApp"> <head> <meta ...

  6. 三点须知:当我们在开发过程中需要用到分布式缓存Redis的时候

    当我们在开发过程中需要用到分布式缓存Redis的时候,我们首先要明白缓存在系统中用来做什么? 1. 少量数据存储,高速读写访问.通过数据全部in-momery 的方式来保证高速访问,同时提供数据落地的 ...

  7. 【Python进阶】无论API怎么变,SDK都可以根据URL实现完全动态的调用

    现在很多网站都搞REST API,比如新浪微博.豆瓣啥的,调用API的URL类似: http://api.server/user/friends http://api.server/user/time ...

  8. python基础知识-03-字符串

    python其他知识目录 1.for循环遍历字符串中单个字符 s_str="mcw" for i in s_str: print(i) -----------结果: m c w 2 ...

  9. CQOI2018 游记 再见OI,既是反思,也是祝福

    哎,怎么说呢? 时运不齐,命途多舛? 从头开始说吧. 今年的NOIP大家考的都不尽人意,每个人都有或多或少的失误,全部都几十分几十分地丢.最后大家剩下的觉得可能冲击一下省队的人一共只有7个. 伙伴们变 ...

  10. Alpha 冲刺(4/10)

    队名 火箭少男100 组长博客 林燊大哥 作业博客 Alpha 冲鸭鸭鸭鸭! 成员冲刺阶段情况 林燊(组长) 过去两天完成了哪些任务 协调各成员之间的工作 协助前后端接口的开发 测试项目运行的服务器环 ...