[CF765F]Souvenirs
[CF765F]Souvenirs
题目大意:
给定一个长度为\(n(n\le2\times10^5)\)的数列\(A_{1\sim n}\),\(m(m\le3\times10^5)\)次询问,每次询问区间\([l,r]\)内两个不相等的数之差的最小值。
思路:
将所有询问离线,按右端点排序。
枚举右端点\(r\),用线段树维护对于当前的右端点,每个左端点对应的答案。
线段树每个结点维护对应区间归并排序后的状态,即构造一棵归并树。
插入新的右端点就相当于在线段树对应区间找到最接近的数,然后更新答案。
显然暴力更新的复杂度在最坏情况下是单次\(\mathcal O(n)\)的。
发现由于右端点固定,若左边的答案已经不会比右边优,则左端点已经没有更新的必要。先更新右子区间,再更新左子区间剪枝即可。
时间复杂度\(\mathcal O(m\log^2 n)\)。
源代码:
#include<cstdio>
#include<cctype>
#include<vector>
#include<climits>
#include<algorithm>
inline int getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int x=ch^'0';
while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
return x;
}
const int N=2e5+1,M=3e5;
int a[N],ans[M],min;
struct Query {
int l,r,id;
bool operator < (const Query &rhs) const {
return r<rhs.r;
}
};
Query q[M];
class SegmentTree {
#define _left <<1
#define _right <<1|1
#define _par >>1
#define mid ((b+e)>>1)
private:
int val[N<<2];
std::vector<int> v[N<<2];
public:
void build(const int &p,const int &b,const int &e) {
val[p]=INT_MAX;
if(b==e) {
v[p].push_back(a[b]);
return;
}
build(p _left,b,mid);
build(p _right,mid+1,e);
v[p].resize(e-b+1);
std::merge(v[p _left].begin(),v[p _left].end(),v[p _right].begin(),v[p _right].end(),v[p].begin());
}
void modify(const int &p,const int &b,const int &e,const int &r,const int &x) {
if(r==e) {
auto it=std::lower_bound(v[p].begin(),v[p].end(),x);
if(it<v[p].end()) val[p]=std::min(val[p],std::abs(x-*it));
if(--it>=v[p].begin()) val[p]=std::min(val[p],std::abs(x-*it));
if(val[p]>=min) return;
if(b==e) {
min=val[p];
return;
}
}
if(r>mid) modify(p _right,mid+1,e,r,x);
modify(p _left,b,mid,std::min(mid,r),x);
val[p]=std::min(val[p _left],val[p _right]);
min=std::min(min,val[p]);
}
int query(const int &p,const int &b,const int &e,const int &l,const int &r) const {
if(b==l&&e==r) return val[p];
int ret=INT_MAX;
if(l<=mid) ret=std::min(ret,query(p _left,b,mid,l,std::min(mid,r)));
if(r>mid) ret=std::min(ret,query(p _right,mid+1,e,std::max(mid+1,l),r));
return ret;
}
#undef _left
#undef _right
#undef _par
#undef mid
};
SegmentTree t;
int main() {
const int n=getint();
for(register int i=1;i<=n;i++) a[i]=getint();
const int m=getint();
for(register int i=0;i<m;i++) {
const int l=getint(),r=getint();
q[i]={l,r,i};
}
std::sort(&q[0],&q[m]);
t.build(1,1,n);
for(register int i=2,j=0;i<=n;i++) {
min=INT_MAX;
t.modify(1,1,n,i-1,a[i]);
for(;j<m&&q[j].r==i;j++) {
ans[q[j].id]=t.query(1,1,n,q[j].l,q[j].r-1);
}
}
for(register int i=0;i<m;i++) {
printf("%d\n",ans[i]);
}
return 0;
}