【CF765F】Souvenirs

题意:给你一个长度为n的序列{ai},有m个询问,每次询问给出l,r,问在所有$l\le x < y\le r$中,$|a_x-a_y|$的最小值是多少。

$n\le 10^5,m\le 3\times 10^5,a_i\le 10^9$

题解:网上的标程都是在线段树上搞一搞就完事了,但是我怎么看都觉得是$O(n\log^3n)$的。看官方题解,里面也没写具体做法。于是我一脸懵逼的情况下用了主席树来维护,起码保证了$O(n\log^2n)$的复杂度。(应该是做麻烦了)

说做法吧。我们先只考虑$j<i,a_j>a_i$的情况,然后反过来再做一遍。首先比较暴力的思路就是先将询问离线,按右端点排序,然后枚举右端点。当我们扫到一个右端点i的时候,先找到i左边第一个比它大的数j,用$a_j-a_i$更新j左边的答案,然后不断找到j左边,比$a_j$小,比$a_i$大的j',重复此步骤做下去。

而一个比较重要的性质就是我们找到的j'只有在满足$a_{j'}-a_i<a_j-a_{j'}$的情况下才是有意义的(否则就用$a_j-a_{j'}$做答案了),所以每次我们的差都会减半,所需次数为log次。如果用树状数组更新答案的话复杂度就是$O(n\log n\log a_i)$的了。

但是怎么找到下一个$j'$呢?我比较菜所以用的主席树。

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
int n,m,N,top,pre,tot;
const int maxn=100010;
int v[maxn],st[maxn],sn[maxn],ans[maxn*3],p[maxn],rk[maxn],ref[maxn],rt[maxn];
struct node
{
int x,org;
node() {}
node(int a,int b) {x=a,org=b;}
};
vector<node> q[maxn];
vector<node>::iterator it;
int val[maxn<<2];
struct sag
{
int ls,rs,siz;
}s[maxn*20];
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();
return ret*f;
}
bool cmp(const int &a,const int &b) {return v[a]<v[b];}
inline void updata(int x,int val)
{
for(int i=x;i;i-=i&-i) sn[i]=min(sn[i],val);
}
inline int query(int x)
{
int ret=1<<30;
for(int i=x;i<=n;i+=i&-i) ret=min(ret,sn[i]);
return ret;
}
inline void insert(int x,int &y,int l,int r,int a)
{
y=++tot,s[y].ls=s[x].ls,s[y].rs=s[x].rs,s[y].siz=s[x].siz+1;
if(l==r) return ;
int mid=(l+r)>>1;
if(a<=mid) insert(s[x].ls,s[y].ls,l,mid,a);
else insert(s[x].rs,s[y].rs,mid+1,r,a);
}
inline int getrank(int x,int y,int l,int r,int a)
{
if(l==r) return s[y].siz-s[x].siz;
int mid=(l+r)>>1;
if(a<=mid) return getrank(s[x].ls,s[y].ls,l,mid,a);
return s[s[y].ls].siz-s[s[x].ls].siz+getrank(s[x].rs,s[y].rs,mid+1,r,a);
}
inline int find(int x,int y,int l,int r,int a)
{
if(l==r) return l;
int mid=(l+r)>>1,t=s[s[y].ls].siz-s[s[x].ls].siz;
if(a<=t) return find(s[x].ls,s[y].ls,l,mid,a);
return find(s[x].rs,s[y].rs,mid+1,r,a-t);
}
void work()
{
int i,j,t,last;
for(i=1;i<=n;i++) p[i]=i;
sort(p+1,p+n+1,cmp);
for(N=0,i=1;i<=n;i++)
{
if(i==1||v[p[i]]>v[p[i-1]]) ref[++N]=v[p[i]];
rk[p[i]]=N;
}
ref[0]=-1<<30,ref[N+1]=1<<30;
tot=0;
for(i=1;i<=n;i++) insert(rt[rk[p[i-1]]],rt[rk[p[i]]],1,n,p[i]);
memset(sn,0x3f,sizeof(sn));
for(st[top=0]=0,i=1;i<=n;i++)
{
while(top&&rk[st[top]]<rk[i]) top--;
last=st[top];
while(last)
{
updata(last,v[last]-v[i]);
if(rk[last]==rk[i]) break;
pre=0;
j=upper_bound(ref+1,ref+N+1,(v[last]+v[i])>>1)-ref-1;
if(ref[j]<v[i]) break;
t=getrank(rt[rk[i]-1],rt[j],1,n,i);
if(t==1) break;
last=find(rt[rk[i]-1],rt[j],1,n,t-1);
}
for(it=q[i].begin();it!=q[i].end();it++) ans[(*it).org]=min(ans[(*it).org],query((*it).x));
st[++top]=i;
}
}
int main()
{
n=rd();
int i,a,b;
for(i=1;i<=n;i++) v[i]=rd();
m=rd();
memset(ans,0x3f,sizeof(ans));
for(i=1;i<=m;i++) a=rd(),b=rd(),q[b].push_back(node(a,i));
work();
for(i=1;i<=n;i++) v[i]=-v[i];
work();
for(i=1;i<=m;i++) printf("%d\n",ans[i]);
return 0;
}//3 1 1 1 1 1 2

【CF765F】Souvenirs 主席树的更多相关文章

  1. Codeforces.765F.Souvenirs(主席树)

    题目链接 看题解觉得非常眼熟,总感觉做过非常非常类似的题啊,就是想不起来=v=. 似乎是这道...也好像不是. \(Description\) 给定长为\(n\)的序列\(A_i\).\(m\)次询问 ...

  2. CF765F Souvenirs

    CF765F Souvenirs [CF765F]Souvenirs 主席树 - CQzhangyu - 博客园 其实不用主席树 感觉像是离线问题 但是不能支持差分.分治又处理不了 考虑按照右端点排序 ...

  3. Codeforces 765F Souvenirs 线段树 + 主席树 (看题解)

    Souvenirs 我们将询问离线, 我们从左往右加元素, 如果当前的位置为 i ,用一棵线段树保存区间[x, i]的答案, 每次更新完, 遍历R位于 i 的询问更新答案. 我们先考虑最暴力的做法, ...

  4. CF765F Souvenirs 解题报告

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

  5. bzoj3207--Hash+主席树

    题目大意: 给定一个n个数的序列和m个询问(n,m<=100000)和k,每个询问包含k+2个数字:l,r,b[1],b[2]...b[k],要求输出b[1]~b[k]在[l,r]中是否出现. ...

  6. bzoj1901--树状数组套主席树

    树状数组套主席树模板题... 题目大意: 给定一个含有n个数的序列a[1],a[2],a[3]--a[n],程序必须回答这样的询问:对于给定的i,j,k,在a[i],a[i+1],a[i+2]--a[ ...

  7. BZOJ 3626: [LNOI2014]LCA [树链剖分 离线|主席树]

    3626: [LNOI2014]LCA Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2050  Solved: 817[Submit][Status ...

  8. BZOJ 1146: [CTSC2008]网络管理Network [树上带修改主席树]

    1146: [CTSC2008]网络管理Network Time Limit: 50 Sec  Memory Limit: 162 MBSubmit: 3522  Solved: 1041[Submi ...

  9. BZOJ 2588: Spoj 10628. Count on a tree [树上主席树]

    2588: Spoj 10628. Count on a tree Time Limit: 12 Sec  Memory Limit: 128 MBSubmit: 5217  Solved: 1233 ...

随机推荐

  1. GWAS文献解读:The stability of educational achievement across school years is largely explained by genetic factors

    方法 从NPD(英国数据库,收集有关学生在学年中学业成绩的数据)和TEDS(英国国家课程指南报告成绩数据库,由国家教育研究基金会和资格与课程管理局制定标准化核心学术课程)数据库获得双胞胎的学业成绩数据 ...

  2. 时间序列分析模型——ARIMA模型

    时间序列分析模型——ARIMA模型 一.研究目的 传统的经济计量方法是以经济理论为基础来描述变量关系的模型.但经济理论通常不足以对变量之间的动态联系提供一个严密的说明,而且内生变量既可以出现在方程的左 ...

  3. Java异常知识整理_处理异常时的性能开销

    1.首先列两个从别的地方看到的说法: try-catch代码段会产生额外的性能开销,或者换个角度说,它往往会影响JVM对代码进行优化,所以建议仅捕获有必要的代码段,尽量不要一个大的try包住整段的代码 ...

  4. MySQL初步

    一 写在开头1.1 本节内容本节的主要内容是MySQL的基本操作(来自MySQL 5.7官方文档). 1.2 工具准备一台装好了mysql的ubuntu 16.04 LTS机器. 二 MySQL的连接 ...

  5. django - 总结

    0.html-socket import socket def handle_request(client): request_data = client.recv(1024) print(" ...

  6. npm常用命令学习(npm install -D,semver版本规范, npm进行版本管理的最佳实践用法)

    什么是npm npm有两层含义.一层含义是Node的开放式模块登记和管理系统,网址为npmjs.org.另一层含义是Node默认的模块管理器,是一个命令行下的软件,用来安装和管理Node模块. npm ...

  7. 设 $y_1(x), y_2(x)$ 是 $y''+p(x)y'+q(x)y=0$ 的两个解 ($p(x), q(x)$ 连续), 且 $y_1(x_0)=y_2(x_0)=0$, $y_1(x)\not\equiv 0$. 试证: $y_1(x)$, $y_2(x)$ 线性相关.

    设 $y_1(x), y_2(x)$ 是 $y''+p(x)y'+q(x)y=0$ 的两个解 ($p(x), q(x)$ 连续), 且 $y_1(x_0)=y_2(x_0)=0$, $y_1(x)\n ...

  8. [物理学与PDEs]第1章习题4 偶极子的极限电势

    对在 $P_0$ 及 $P_1$ 处分别置放 $-q$ 及 $+q$ 的点电荷所形成的电偶极子, 其偶极距 ${\bf m}=q{\bf l}$, ${\bf l}=\vec{P_0P_1}$. 试证 ...

  9. Best Practice API

    # 建议直接使用的第三方类 Common Lang =>StringUtils =>Validate Guava =>Cache =>Ordering JDK7(LTS JDK ...

  10. java.util.zip.ZipException: invalid entry size

    启动maven项目时报java.util.zip.ZipException: invalid entry size (expected 7612 but got 5955 bytes) 可能是mave ...