[CF765F]Souvenirs

[CF765F]Souvenirs

题目大意:

给定一个长度为(n(nle2 imes10^5))的数列(A_{1sim n})(m(mle3 imes10^5))次询问,每次询问区间([l,r])内两个不相等的数之差的最小值。

思路:

将所有询问离线,按右端点排序。

枚举右端点(r),用线段树维护对于当前的右端点,每个左端点对应的答案。

线段树每个结点维护对应区间归并排序后的状态,即构造一棵归并树。

插入新的右端点就相当于在线段树对应区间找到最接近的数,然后更新答案。

显然暴力更新的复杂度在最坏情况下是单次(mathcal O(n))的。

发现由于右端点固定,若左边的答案已经不会比右边优,则左端点已经没有更新的必要。先更新右子区间,再更新左子区间剪枝即可。

时间复杂度(mathcal O(mlog^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
",ans[i]);
	}
	return 0;
}	
原文地址:https://www.cnblogs.com/skylee03/p/9484014.html