CF765F Souvenirs 题解

题目询问在区间\([l,r]\)内满足\(l \le i < j \le r\)这一条件的最小的\(|a_i-a_j|\)
首先有一个想法是离线下来询问,然后对于每一个\(i\)找住\(j\)满足\(j<i\)\(a_j>a_i\),(绝对值把\(a_i\)变为\(1e9-a_i\),也就是反过来即可)。
但是找到所有\(j\)复杂度过高,不可以接受,我们考虑那些\(j\)可以对答案产生影响。
假设我们现在处理的点是\(i\),刚修改过的点是\(j\),我们考虑\(k<i\)\(a_k<a_j,a_k>=a_i\)
如果要\(a_k-a_i\)最优,需要保证\(a_k-a_i<a_j-a_k\),移向得\(a_k-a_i < \frac{1}{2} (a_j-a_i)\)
每次值域缩小一半,复杂度为\(n \log2(n)^2\)

代码:

#include <bits/stdc++.h>
#define int long long
#define mid ((l+r)/2)
using namespace std;
const int maxn=1e5+10;
int n,ans[maxn<<2],a[maxn],pos,jie=1e9,idd,m,x,y,rt,C[maxn];
struct edge{
	int ls;
	int rs;
	int mx;
}tree[maxn<<5];
vector<pair<int,int> >xun[maxn];
int lowbit(int q){
	return q&(-q);
}
void add(int q,int w){
	for(int i=q;i;i-=lowbit(i)){
		C[i]=min(C[i],w);
	}
	return;
}
int query(int q){
	int mn=jie;
	for(int i=q;i<=n;i+=lowbit(i)){
		mn=min(mn,C[i]);
	}
	return mn;
}
void add(int &id,int l,int r,int q,int w){
	if(!id){
		idd++;
		id=idd;
	}
	if(l==r){
		tree[id].mx=w;
		return;
	}
	if(q<=mid){
		add(tree[id].ls,l,mid,q,w);
	}
	else{
		add(tree[id].rs,mid+1,r,q,w);
	}
	tree[id].mx=max(tree[tree[id].ls].mx,tree[tree[id].rs].mx);
	return;
}
int query(int id,int l,int r,int q,int w){
	if(q>w){
		return 0;
	}
	if(q<=l&&r<=w){
		return tree[id].mx;
	}
	if(w<=mid){
		return query(tree[id].ls,l,mid,q,w);
	}
	else if(q>mid){
		return query(tree[id].rs,mid+1,r,q,w);
	}
	else{
		return max(query(tree[id].ls,l,mid,q,w),query(tree[id].rs,mid+1,r,q,w));
	}
}
void solve(){
	memset(C,0x3f,sizeof(C));
	for(int i=1;i<=idd;i++){
		tree[i].ls=0;
		tree[i].rs=0;
		tree[i].mx=0;
	}
	idd=0;
	rt=0;
	for(int i=1;i<=n;i++){
		pos=query(rt,0,jie,a[i],jie);
		while(pos){
			add(pos,a[pos]-a[i]);
			pos=query(rt,0,jie,a[i],a[i]+(a[pos]-a[i]+1)/2-1);
		}
		add(rt,0,jie,a[i],i);
		for(int j=0;j<xun[i].size();j++){
			ans[xun[i][j].second]=min(ans[xun[i][j].second],query(xun[i][j].first));
		}
	}
	return;
}
signed main(){
	ios::sync_with_stdio(0);
	cin.tie(0),cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i];
	}
	cin>>m;
	for(int i=1;i<=m;i++){
		cin>>x>>y;
		xun[y].push_back({x,i});
		ans[i]=jie;
	}
	solve();
	for(int i=1;i<=n;i++){
		a[i]=jie-a[i];
	}
	solve();
	for(int i=1;i<=m;i++){
		cout<<ans[i]<<'\n';
	}
	return 0;
}
posted @ 2025-04-28 18:14  特别之处  阅读(11)  评论(0)    收藏  举报