题目大意

给定一个序列
多次询问一个区间最接近两个数的差值
最接近的两个数可以相同,但不能是同一个位置上的数。
允许离线

强大线段树做法

我们首先可以扫描线
从左到右扫,每次处理右端点在扫描线上的所有询问。
我们维护一颗线段树,线段树每个节点的值没有太多实际的意义,但它需要满足一个性质:
假如当前扫描线在now,那么在线段树中查询[l,now]这个区间的答案就是正确的答案
听起来很不可思议?
这样每次询问直接询问即可
我们思考每次从now-1到now,线段树哪些信息需要更改,此时我们加入了一个a[now],设为d。
我们可以先去定位区间[1,now],规定优先走右儿子。
对于一个被定位的区间[L,R]满足R<=now,什么情况下不需要在对它包括它子树的信息进行更改了呢?
因为我们优先走右儿子,那么我们可以维护出一个mi表示此时[R+1,now]的答案。
假如对于[L,R],d在[L,R]中找到的每一个数t(注意如果R=now,t并不能去a[now]),都有|d−t|>=mi|d-t|>=mi,那么这个点上的值不更改也可以满足我们线段树需要满足的条件,即询问[i,now]得到正确的答案。于是我们更新mi后直接退出。
否则的话,我们可能要更改这个区间上的值,我们暴力递归左右,这里也是优先走右边。
为了验证是否还需要往下做,每个区间维护一个set,每次给d找前驱和后继即可。
因为不能包含a[now],所以每次做完修改再把now所处的区间的set里都塞一个a[now]。
这样做正确性是没有问题的,时间复杂度如何呢?
我们只需要考虑一直递归到叶子的位置,其他的都是区间,区间定位的复杂度会和递归到叶子保持一致(假设相邻两个递归到叶子的位置i和j,那么在到i叶子路径和到j叶子路径第一次分开后,i那条每往左走右边那个区间被定位为[i+1,j-1]里的直接退出,j那条同理,可以看出两者复杂度同阶)。
一个位置i什么时候会被递归到叶子,显然是[i,now]的答案比[i+1,now]优秀。考虑最坏情况,就是序列1 n n/2 n/4 n/8……每次值会减一半,可以分析出一个位置只会被递归到叶子log次!
算上set的复杂度,感觉应该是三个log?实际跑起来会比较玄学。

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<set>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=100000+10,maxm=300000+10,inf=2000000000;
struct dong{int l,r,id;
} ask[maxm];
int tree[maxn*4],ans[maxm],a[maxn],sta[80];
set<int> e[maxn*4];
int i,j,k,l,r,t,n,m,mi,top;
int read(){int x=0,f=1;char ch=getchar();while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*f;
}
bool cmp(dong a,dong b){return a.r<b.r;
}
void build(int p,int l,int r){tree[p]=inf;if (l==r) return;int mid=(l+r)/2;build(p*2,l,mid);build(p*2+1,mid+1,r);
}
void change(int p,int l,int r,int qr,int d){if (l==r){if (l==qr) return;tree[p]=min(tree[p],abs(d-a[l]));mi=min(mi,tree[p]);return;}if (r<=qr){set<int>::iterator it=e[p].lower_bound(d);if ((it==e[p].end()||abs(*it-d)>=mi)&&(it==e[p].begin()||abs(*(--it)-d)>=mi)){mi=min(mi,tree[p]);return;}int mid=(l+r)/2;change(p*2+1,mid+1,r,qr,d);change(p*2,l,mid,qr,d);tree[p]=min(tree[p*2],tree[p*2+1]);return;}int mid=(l+r)/2;if (qr<=mid) change(p*2,l,mid,qr,d);else{change(p*2+1,mid+1,r,qr,d);change(p*2,l,mid,qr,d);}tree[p]=min(tree[p*2],tree[p*2+1]);
}
void cr(int p,int l,int r,int a,int b){e[p].insert(b);if (l==r) return;int mid=(l+r)/2;if (a<=mid) cr(p*2,l,mid,a,b);else cr(p*2+1,mid+1,r,a,b);
}
int query(int p,int l,int r,int a,int b){if (l==a&&r==b) return tree[p];int mid=(l+r)/2;if (b<=mid) return query(p*2,l,mid,a,b);else if (a>mid) return query(p*2+1,mid+1,r,a,b);else return min(query(p*2,l,mid,a,mid),query(p*2+1,mid+1,r,mid+1,b));
}
void write(int x){if (!x){putchar('0');putchar('\n');return;}top=0;while (x){sta[++top]=x%10;x/=10;}while (top){putchar('0'+sta[top]);top--;}putchar('\n');
}
int main(){//freopen("data.in","r",stdin);n=read();fo(i,1,n) a[i]=read();build(1,1,n);m=read();fo(i,1,m) ask[i].l=read(),ask[i].r=read(),ask[i].id=i;sort(ask+1,ask+m+1,cmp);r=0;fo(i,1,m){while (r<ask[i].r){r++;mi=inf;change(1,1,n,r,a[r]);cr(1,1,n,r,a[r]);}ans[ask[i].id]=query(1,1,n,ask[i].l,r);}fo(i,1,m) write(ans[i]);
}

[CF765F]Souvenirs相关推荐

  1. CF765F Souvenirs 解题报告

    CF765F Souvenirs 题意翻译 给出\(n(2 \le n \le 10^5 )\) ,一个长为\(n\)的序列\(a(0 \le a_i \le 10^9 )\). 给出\(m(1\le ...

  2. CF765F Souvenirs(势能线段树)

    CF765F Souvenirs problem solution code problem 题目链接 solution 这个势能线段树简直是太巧妙了!!!( ఠൠఠ )ノ 将询问按右端点升序离线下来 ...

  3. # CF765F Souvenirs

    CF765F Souvenirs 将询问按照右端点记录下来. 我们考虑从左向右处理每一个 aia_iai​ 对它前面的所有区间 [l,i](l∈[1,i])[l, i] ~~(l \in [1,i]) ...

  4. CF765F Souvenirs

    题目 先看暴力做法. 把询问按右端点升序排序. 对于每个\(r\),我们处理出左端点\(l\in[1,r)\)的所有答案\(ans_l\),当\(r\)向右扩展时暴力修改\(ans\). 这样子显然不 ...

  5. CF765F Souvenirs(暴力、线段树)

    解析 比较神奇的一道题. 考虑一个常规套路:把询问离线,移动右端点,维护左端点答案. 考虑暴力维护,对于当前的 ai=xa_i=xai​=x,左侧如图所示的这两条线上的点都可以产生新的可能答案. 容易 ...

  6. [CF765F] Souvenirs

    Portal 其实这题很套路.像HNOI2017影魔的模型,大概可以概括为: 给定你一个序列,在不修改的前提下,求一个区间满足某种条件的二元组的个数/最值/和,条件一般和最值有关, 这就方便我们进行维 ...

  7. 暑假训练-义乌(7.8-7.15)

    暑假训练 模拟赛 图表 数据 7.8(lxl) 7.9(lxl) 7.10(lxl) 7.11(lxl) 7.12(wls) 7.13(wls) 7.14(wls) 7.15(lfds) 训练 数据结 ...

  8. hdu2126 Buy the souvenirs 01背包变形 dp

    链接:点我 题意:n个物品,m元钱,每个物品最多买一次,问最多可以买几件物品,并且输出方案数.加一维表示已经买几件物品. 我这里用了一个数组dp[v][2] ,dp[v][0] 储存原本要记录的 dp ...

  9. 【ICPC-283】hdu 2126 Buy the souvenirs(二维0/1背包)

    点击打开链接hdu2126 思路: 二维0/1背包 分析: 1 题目给定n个物品的价钱和m的钱,问最多能买到的物品数有几种方案. 2 很明显就可以写出状态转移方程dp[i][j][k]表示的是前i个物 ...

最新文章

  1. Linux - SVN下载项目
  2. SSL证书如何工作?
  3. php数组为什么其他语言,PHP语言特性和各版本的差异
  4. 双指针:88. 合并两个有序数组
  5. ntp协议中 服务器失效怎么办,排除网络时间协议(NTP)故障
  6. jsp或java中前后台传值乱码解决
  7. 进阶~Qt程序启动画面_vortex_新浪博客
  8. 设置占用GPU的比例
  9. 试验设计与matlab数据分析 下载,试验设计与MATLAB数据分析
  10. SiamFC复现结果
  11. JAVA实战小项目——图书馆管理系统
  12. java爬虫正则表达式_Java爬虫预热之正则表达式 - 菜鸟头头
  13. 京东非自营下运费模式
  14. 传感器实验——LCD屏幕测试
  15. 推荐系统从入门到接着入门
  16. 基于阿里云服务器ECS和宝塔面板,适合初学者的蚂蚁笔记(Leanote)超详细配置教程(但是真的不好用)
  17. iphone6 适配和分辨率
  18. cpu对各种运算的速度对比
  19. 哪个邮箱安全性好?电子邮箱注册怎么申请163邮箱?
  20. IP 分支组网解决方案

热门文章

  1. 浅谈单调队列优化的DP
  2. 浪潮服务器2003系统,浪潮服务器安装WINDOWS 2003操作系统课件.ppt
  3. 强化学习(9):TRPO、PPO以及DPPO算法
  4. 【C++ 程序】 Fractal Designer 0.2
  5. 通达信 红线精准主升浪波段买卖选股指标 蝶形飞扬副图公式源码
  6. 为什么毕业的第一份工作要进FLAG?
  7. SE5_基于YOLO3D的目标检测算法移植与测试
  8. linux修改文件夹的访问权限,linux setfacl chmod g+s 修改文件夹和文件的默认访问权限和所属组...
  9. bitmap file res\xxx.png is not in 3.00 format
  10. C++实现简易的画图软件