[CF765F]Souvenirs
来源:互联网 发布:30多了能做网络主播吗? 编辑:程序博客网 时间:2024/05/22 03:06
题目大意
给定一个序列
多次询问一个区间最接近两个数的差值
最接近的两个数可以相同,但不能是同一个位置上的数。
允许离线
强大线段树做法
我们首先可以扫描线
从左到右扫,每次处理右端点在扫描线上的所有询问。
我们维护一颗线段树,线段树每个节点的值没有太多实际的意义,但它需要满足一个性质:
假如当前扫描线在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]),都有
否则的话,我们可能要更改这个区间上的值,我们暴力递归左右,这里也是优先走右边。
为了验证是否还需要往下做,每个区间维护一个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
- buy souvenirs
- HDU2126:Buy the souvenirs
- 2126 Buy the souvenirs
- hdu2126 Buy the souvenirs
- 【HDU2126】【Buy the souvenirs】
- souvenirs without help
- Codeforces 765F. Souvenirs
- 【题解】codeforces765F Souvenirs
- 808E. Selling Souvenirs***
- E. Selling Souvenirs
- hdu 2126 Buy the souvenirs
- hdu 2126 Buy the souvenirs
- Buy the souvenirs(hdu(2126)
- HDU 2126 Buy the souvenirs
- HDU 2126 Buy the souvenirs
- hdu2126 Buy the souvenirs (01)
- HDU2126:Buy the souvenirs(01)
- DMIS Vector variable values / DMIS语言中向量变量用法介绍
- centOS7查看runlevel
- 解决github-pages无法被百度抓取问题(octopress)
- Android系统中打印堆栈的方法
- Xcode8制作.a静态库和存放xib和图片的.bundle
- [CF765F]Souvenirs
- 物理层协议有哪四大特性
- 关于Vue的一些小用法(记录)
- 前端构建工具gulpjs
- 在linux上用RPM包安装mysql
- android之AIDL跨进程通信详解
- SPOJ FACVSPOW
- 导入已有项目时Building project info 卡住了(解决方法)
- 个推你应该这样用的