CF765F Souvenirs
CF765F Souvenirs
可以发现这个问题类似询问区间逆序对(都和排序相关,都和点对相关),于是我们可以顺着 P5046 的方法去想。
分块。把询问分成询问端点同块与询问端点异块的情况。
询问端点同块
此时可以考虑处理出每个块排序后的数组。沿着排序后的数组,按大小顺序地“取出”
询问端点异块
参照 P5046 分成如下几部分:
- 散块内部与散块之间
- 整块与散块之间
- 整块内部与整块之间
散块内部与散块之间
与询问端点同块情况类似,取出两个散块分别得排序后的状态,归并起来,然后统计,我直接用了 STL。
整块与散块之间
预处理两个数组:
那如何预处理呢?可以考虑先处理 一个位置对一个块的答案,再前缀和变成 一个前缀/后缀对一个块的答案,再前缀和成 一个前缀/后缀对一些块的答案。
那 一个位置对一个块的答案 怎么算呢?可以先钦定两个块
具体算法为:块
这两个数组没有相交的地方,考虑将其合并。
整块内部与整块之间
考虑预处理
可以先处理
代码
感觉写的还算简单,100 行不到。
#include<stdio.h>
#include<math.h>
#include<algorithm>
const int SIZ = 1000000;
namespace IO{ // by OneZzz6174
using IO::read;
using IO::readc;
using IO::print;
using IO::flush;
#define rint register int
#define rep(i,a,b) for(rint i = (a);i <= (b);++i)
#define Rep(i,a,b) for(rint i = (a);i >= (b);--i)
inline int max2(rint a,rint b){ return a>b?a:b; }
inline int min2(rint a,rint b){ return a<b?a:b; }
inline int chkmax(rint &a,rint b){ return a=a>b?a:b; }
inline int chkmin(rint &a,rint b){ return a=a<b?a:b; }
inline int abs2(rint x){ return x>0?x:-x; }
const int maxn = 1e5 + 5;
const int sqr = 325;
const int inf = 1e9 + 5;
int n,m,a[maxn],B,C;
int D[maxn][sqr],S[sqr][sqr];
int st[sqr],ed[sqr],bl[maxn];
int tmp[maxn];
struct value{
int i,x;
bool operator<(const value& v) const {
return x < v.x;
}
} b[maxn];
int qry0(rint l,rint r){
int ans = inf,len = 0;
rep(i,st[bl[l]],ed[bl[l]])
if(l <= b[i].i && b[i].i <= r) tmp[++len] = b[i].x;
rep(i,2,len) chkmin(ans,tmp[i] - tmp[i - 1]);
return ans;
}
int qry1(rint l1,rint r1,rint l2,rint r2){
int len = 0,p = r1 - l1 + 1,ans = inf;
rep(i,st[bl[l1]],ed[bl[l1]])
if(l1 <= b[i].i && b[i].i <= r1) tmp[++len] = b[i].x;
rep(i,st[bl[l2]],ed[bl[l2]])
if(l2 <= b[i].i && b[i].i <= r2) tmp[++len] = b[i].x;
std::inplace_merge(tmp + 1,tmp + p + 1,tmp + len + 1);
rep(i,2,len) chkmin(ans,tmp[i] - tmp[i - 1]);
return ans;
}
void init(){
B = sqrt(n); C = (n - 1) / B + 1;
rep(i,1,C){
st[i] = (i - 1) * B + 1;
ed[i] = i == C ? n : i * B;
rep(j,st[i],ed[i]) bl[j] = i,b[j].i = j,b[j].x = a[j];
std::sort(b + st[i],b + ed[i] + 1);
}
rep(i,1,C){
rep(j,1,C) if(i ^ j){
rint p = st[j];
rep(k,st[i],ed[i]){
while(p < ed[j] && b[p + 1].x < b[k].x) ++p;
D[b[k].i][j] = abs2(b[k].x - b[p].x);
if(p < ed[j]) chkmin(D[b[k].i][j],abs2(b[k].x - b[p + 1].x));
}
}
rep(j,st[i],ed[i]) rep(k,i + 2,C) chkmin(D[j][k],D[j][k - 1]);
rep(j,st[i],ed[i]) Rep(k,i - 2,0) chkmin(D[j][k],D[j][k + 1]);
rep(k,1,i - 1) rep(j,st[i] + 1,ed[i]) chkmin(D[j][k],D[j - 1][k]);
rep(k,i + 1,C) Rep(j,ed[i] - 1,st[i]) chkmin(D[j][k],D[j + 1][k]);
S[i][i] = qry0(st[i],ed[i]);
}
rep(i,1,C) rep(j,i + 1,C) S[i][j] = min2(min2(S[i][j - 1],S[j][j]),D[ed[j]][i]);
}
int qry(rint l,rint r){
if(bl[l] == bl[r]) return qry0(l,r);
int ans = qry1(l,ed[bl[l]],st[bl[r]],r);
if(bl[l] + 1 <= bl[r] - 1){
chkmin(ans,S[bl[l] + 1][bl[r] - 1]);
chkmin(ans,min2(D[r][bl[l] + 1],D[l][bl[r] - 1]));
}
return ans;
}
int main(){
read(n); rep(i,1,n) read(a[i]);
init(); read(m);
while(m--){
int l,r; read(l,r);
print(qry(l,r),'\n');
}
return flush(),0;
}