[CF765F]Souvenirs

codeforces

description

给你一个数列({a_i}),每次询问一段区间([l,r])内两数之差的最小值。
(nle10^5,mle3 imes10^5,a_ile10^9)

sol

首先询问离线,然后向右移动右端点,维护左端点的答案。为了方便,我们只考虑用(j<i,a_j>a_i)的点对去更新答案,剩下的可以把(a_i)的值域翻转然后再做一遍。
假设现在右端点在(i),我们先找到(max{j|a_j>a_i}),这样就可以用(a_j-a_i)更新左端点在([1,j])的答案。然后我们希望找一个(j'<j)满足(a_{j'}ge a_i)(a_{j'}-a_i<a_j-a_i),这样就可以进一步更新答案。接着可以令(j=j'),重复之间的操作,直至找不到一个满足条件的(j')为止。
但其实,这个限制条件可以进一步写为(a_{j'}-a_i<a_j-a_{j'})
很简单,因为在这之前(a_j-a_{j'})就已经更新过答案了,所以要想进一步更新除非答案更优。
移项可得(a_{j'}-a_i<frac 12(a_j-a_i))。发现每次(a_j)(a_i)的差至少减小一半,所以对于每一个(i),至多存在(O(log10^9))(j)可以更新答案。
那么复杂度就是(O(nlog nlog10^9+mlog n))
至于怎么找到(j'),我直接写的主席树。相当于是找满足值域在一定范围内的下标最大值。

code

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
int gi(){
	int x=0,w=1;char ch=getchar();
	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if (ch=='-') w=0,ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return w?x:-x;
}
const int N = 3e5+5;
const int inf = 1e9;
struct node{int l,r,id;}q[N];
struct seg{int ls,rs,v;}t[N*40];
int n,m,a[N],rt[N],tot,c[N],ans[N];
vector<int>v[N];
void mdf(int k,int v){while(k)c[k]=min(c[k],v),k^=k&-k;}
int qry(int k){int s=ans[0];while(k<=n)s=min(s,c[k]),k+=k&-k;return s;}
void modify(int &x,int l,int r,int p,int v){
	t[++tot]=t[x];x=tot;t[x].v=max(t[x].v,v);
	if (l==r) return;int mid=l+r>>1;
	if (p<=mid) modify(t[x].ls,l,mid,p,v);
	else modify(t[x].rs,mid+1,r,p,v);
}
int query(int x,int l,int r,int ql,int qr){
	if (ql>qr) return 0;
	if (!x||(l>=ql&&r<=qr)) return t[x].v;
	int mid=l+r>>1,s=0;
	if (ql<=mid) s=max(s,query(t[x].ls,l,mid,ql,qr));
	if (qr>mid) s=max(s,query(t[x].rs,mid+1,r,ql,qr));
	return s;
}
void work(){
	memset(c,63,sizeof(c));memset(rt,0,sizeof(rt));
	for (int i=1;i<=tot;++i) t[i]=(seg){0,0,0};tot=0;
	for (int i=1;i<=n;++i) modify(rt[i]=rt[i-1],0,inf,a[i],i);
	for (int i=1;i<=n;++i){
		int j=query(rt[i-1],0,inf,a[i],inf);
		while (j){
			mdf(j,a[j]-a[i]);
			j=query(rt[j-1],0,inf,a[i],(a[i]+a[j]>>1)-(~(a[i]+a[j])&1));
		}
		for (int j:v[i]) ans[q[j].id]=min(ans[q[j].id],qry(q[j].l));
	}
}
int main(){
	n=gi();
	for (int i=1;i<=n;++i) a[i]=gi();
	m=gi();
	for (int i=1;i<=m;++i) q[i]=(node){gi(),gi(),i};
	memset(ans,63,sizeof(ans));
	for (int i=1;i<=m;++i) v[q[i].r].push_back(i);
	work();
	for (int i=1;i<=n;++i) a[i]=inf-a[i];
	work();
	for (int i=1;i<=m;++i) printf("%d
",ans[i]);
	return 0;
}
原文地址:https://www.cnblogs.com/zhoushuyu/p/9537861.html