[2020.11.13]CF765F Souvenirs

题意

给出一个长度为\(n\)的序列\(a\)\(q\)组询问,每次询问一个区间\(l,r\),求\(|a_i-a_j|\)的最小值,其中\(i\ne j\)\(l\le i,j\le r\)

题解

考虑离线,先考虑\(i<j,a_i\le a_j\)的情况,然后把序列翻转考虑另一种情况。

那么,我们枚举\(j\),考虑所有可能成为答案的\(i\),设为\(i_1,i_2,\dots,i_k\),其中\(i_i>i_2>i_3...>i_k\),且\(a_{i_1}<a_{i_2}<a_{i_3}<\dots<a_{i_k}\)

首先,\(i_1\)\(j\)前面第一个小于等于\(a_j\)的数。然后注意到如果\(a_j-a_{i_x}\)要想成为答案必须要比\(a_{i_x}-a_{i_{x-1}}\)要小,即\(a_j-a_{i_x}<a_{i_x}-a_{i_{x-1}}\)变换得到\(2(a_j-a_{i_x})<a_j-a_{i_{x-1}}\)

这也就意味着\(k\)\(O(log)\)级别的。使用主席树找到所有可能作为答案的\((i,j)\)即可。

然后就是从前往后枚举,树状数组维护后缀\(\min\)得到答案。

code:

#include<bits/stdc++.h>
#define ci const int&
using namespace std;
struct Query{
	int p,*pos;
};
struct Val{
	int v,*pos;
}ar[100010];
struct node{
	int l,r,lc,rc,mx;
}t[2000010];
int n,Q,a[100010],rt[100010],cnt,ql[300010],qr[300010],prt[300010],num,mp[100010],tmp,bm[100010];
vector<Query>qi[100010];
void Build0(int&x,ci l,ci r){
	x=++cnt,t[x].l=l,t[x].r=r,t[x].mx=0;
	if(l==r)return(void)(t[x].lc=t[x].rc=0);
	int mid=l+r>>1;
	Build0(t[x].lc,l,mid),Build0(t[x].rc,mid+1,r);
}
void Build(ci lx,int&x,ci id,ci val){
	if(t[lx].l>id||t[lx].r<id)return(void)(x=lx);
	t[x=++cnt].l=t[lx].l,t[x].r=t[lx].r,t[x].mx=val;
	if(t[x].l==t[x].r)return(void)(t[x].lc=t[x].rc=0);
	Build(t[lx].lc,t[x].lc,id,val),Build(t[lx].rc,t[x].rc,id,val);
}
int Find(ci x,ci l,ci r){
	if(r<t[x].l||t[x].r<l)return 0;
	if(l<=t[x].l&&t[x].r<=r)return t[x].mx;
	return max(Find(t[x].lc,l,r),Find(t[x].rc,l,r));
}
bool cmp(Val x,Val y){
	return x.v<y.v;
}
void Ins(int x,ci v){
	x=n-x+1;
	while(x<=n)bm[x]=min(bm[x],v),x+=(x&-x);
}
int Que(int x){
	x=n-x+1;
	int ret=1e9;
	while(x)ret=min(ret,bm[x]),x-=(x&-x);
	return ret;
}
int Get(ci x){
	int l=1,r=num,mid;
	while(l<r)mid=l+r>>1,mp[mid]>=x?r=mid:l=mid+1;
	return l;
}
void Solve(){
	cnt=0,Build0(rt[0],1,num);
	for(int i=1;i<=n;++i)Build(rt[i-1],rt[i],a[i],i),bm[i]=1e9;
	for(int i=1;i<=n;++i){
		tmp=Find(rt[i-1],1,a[i]);
		while(tmp){
			Ins(tmp,mp[a[i]]-mp[a[tmp]]);
			if(a[i]==a[tmp])break;
			tmp=Find(rt[tmp-1],Get(mp[a[i]]-(mp[a[i]]-mp[a[tmp]]-1>>1)),a[i]);
		}
		for(int j=0;j<qi[i].size();++j)(*qi[i][j].pos)=min(*qi[i][j].pos,Que(qi[i][j].p));
	}
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;++i)scanf("%d",&ar[i].v),ar[i].pos=&a[i];
	sort(ar+1,ar+n+1,cmp),ar[0].v=-1;
	for(int i=1;i<=n;++i)num+=(ar[i].v!=ar[i-1].v),mp[num]=ar[i].v,(*ar[i].pos)=num;
	scanf("%d",&Q);
	for(int i=1;i<=Q;++i)scanf("%d%d",&ql[i],&qr[i]),prt[i]=1e9,qi[qr[i]].push_back((Query){ql[i],&prt[i]});
	Solve();
	for(int i=1;i<n-i+1;++i)swap(a[i],a[n-i+1]);
	for(int i=1;i<=n;++i)vector<Query>().swap(qi[i]);
	for(int i=1;i<=Q;++i)qi[n-ql[i]+1].push_back((Query){n-qr[i]+1,&prt[i]});
	Solve();
	for(int i=1;i<=Q;++i)printf("%d\n",prt[i]);
	return 0;
}
posted @ 2020-11-13 21:09  xryjr233  阅读(121)  评论(0编辑  收藏  举报