当前位置: 代码迷 >> 综合 >> 【Codeforces Round #397】Codeforces 765F Souvenirs【解法二】
  详细解决方案

【Codeforces Round #397】Codeforces 765F Souvenirs【解法二】

热度:90   发布时间:2024-01-13 10:31:59.0

解法一(线段树)见这里
我们维护一棵线段树,树上每个结点用平衡树维护含有的元素,并且维护这个区间中的一个值和这个区间右边的另一个值的差的最小值。按区间的左端点从右往左扫描,每次用 ai 对区间 (i,n] 进行覆盖,询问的时候直接询问区间 (l,r] 最小值。
覆盖的时候一般来说需要递归到底,但是这样复杂度还不如暴力。一个重要的剪枝是维护之前已经遍历的区间的前缀最小值【因为递归的过程本来就是前缀实现的】,如果当前区间没有比这个值更优的解,就不再修改,直接返回。
不难发现线段树套平衡树也可以用主席树实现。

#include<cstdio>
#include<algorithm>
#include<set>
#include<vector>
using namespace std;
const int maxn=2000010,oo=0x3f3f3f3f;
int rd()
{int x=0;char c=getchar();while (c<'0'||c>'9') c=getchar();while (c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}return x;
}
set<int> s[maxn];
vector<int> qry[maxn],v[maxn];
int mn[maxn],a[maxn],l[maxn],r[maxn],ans[maxn],
n,q;
void build(int u,int L,int R)
{mn[u]=oo;for (int i=L;i<=R;i++) s[u].insert(a[i]);if (L==R) return;int mid=(L+R)>>1;build(u<<1,L,mid);build(u<<1|1,mid+1,R);
}
int query(int u,int L,int R,int l,int r)
{if (l<=L&&R<=r) return mn[u];int mid=(L+R)>>1;int ret=oo;if (l<=mid) ret=min(ret,query(u<<1,L,mid,l,r));if (r>mid) ret=min(ret,query(u<<1|1,mid+1,R,l,r));return ret;
}
void modify(int u,int L,int R,int l,int r,int x,int &res)
{set<int>::iterator i1=s[u].lower_bound(x),i2;if (i1!=s[u].begin()){i2=i1;i2--;}if ((i1==s[u].end()||*i1-x>=res)&&(i1==s[u].begin()||x-*i2>=res)){res=min(res,query(u,L,R,l,r));return;}/*if (l<=L&&R<=r){if (i1!=s.end()) mn[u]=min(mn[u],*it-x);if (i1!=s.begin()) mu[u]=min(mn[u],x-*it);v[u].push_back(x);}*/if (L==R){mn[u]=min(mn[u],abs(a[L]-x));res=min(res,mn[u]);return;}int mid=(L+R)>>1;if (l<=mid) modify(u<<1,L,mid,l,r,x,res);if (r>mid) modify(u<<1|1,mid+1,R,l,r,x,res);mn[u]=min(mn[u<<1],mn[u<<1|1]);
}
int main()
{int res;n=rd();for (int i=1;i<=n;i++) a[i]=rd();q=rd();for (int i=1;i<=q;i++){l[i]=rd();r[i]=rd();qry[l[i]].push_back(i);}build(1,1,n);for (int i=n-1;i;i--){res=oo;modify(1,1,n,i+1,n,a[i],res);for (vector<int>::iterator it=qry[i].begin();it!=qry[i].end();++it)ans[*it]=query(1,1,n,i+1,r[*it]);}for (int i=1;i<=q;i++) printf("%d\n",ans[i]);
}
  相关解决方案