CF765F Souvenirs
将询问按照右端点记录下来。
我们考虑从左向右处理每一个 a i a_i ai 对它前面的所有区间 [ l , i ] ( l ∈ [ 1 , i ] ) [l, i] ~~(l \in [1,i]) [l,i] (l∈[1,i]) 的贡献,同时求出此时存在的询问。
由于是区间问题,可以考虑线段树。
考虑建一棵值域线段树维护区间内的最靠右的位置是哪。
建一棵线段树维护区间内的最小的 ∣ a i − a j ∣ | a_i - a_j | ∣ai−aj∣ 。
我们考虑右侧新加入一个点会对前面的哪些区间产生贡献。
不难发现,随着向左的扩展, ∣ a i − a j ∣ | a_i - a_j | ∣ai−aj∣ 的值是不断递减的。
我们分别对 a i − a j ( i > j ) a_i - a_j (i > j) ai−aj(i>j) 和 a j − a i ( i > j ) a_j - a_i (i > j) aj−ai(i>j) 进行维护。
(以维护 a i − a j ( i > j ) a_i - a_j (i > j) ai−aj(i>j) 为例)设当前的位置为 k k k ,存在关系 i < j < k i < j < k i<j<k ,
-
a i < a j < a k a_i < a_j < a_k ai<aj<ak ,维护 ( i , k ) (i,k) (i,k) 肯定不优;
-
a j < a i < a k a_j < a_i < a_k aj<ai<ak ,如果 k k k 对 j j j 产生了贡献,如果此时 k k k 要对 i i i 产生贡献,则有:
a k − a i < a i − a j a_k - a_i < a_i - a_j ak−ai<ai−aj
两边同时加上
a
k
−
a
i
a_k - a_i
ak−ai 可以得到:
a
k
−
a
i
<
1
2
(
a
k
−
a
j
)
a_k - a_i < \frac 1 2 (a_k - a_j)
ak−ai<21(ak−aj)
所以就是说,如果一个
a
i
a_i
ai 对它前面的区间有新的贡献,差会减半。
设差为 d d d ,在值域线段树上求出最靠右的满足 a i + d a_i + d ai+d 的位置,修改维护答案的线段树,然后 d d d 减半,重复操作,直到达到边界。时间复杂度 O ( n lg n lg a i ) O(n\lg n \lg a_i) O(nlgnlgai) ,跑得挺快。
细节就看代码吧。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
template <typename T>
inline void read(T &a)
{
T res = 0, sign = 1;
char c;
while ((c = getchar ()) > '9' || c < '0') if (c == '-') sign = -1;
while (c >= '0' && c <= '9')
res = (res << 3) + (res << 1) + c - '0', c = getchar ();
a = res * sign;
}
template <typename T>
inline void print(T a)
{
if (a == 0) {putchar ('0'); return;}
if (a < 0) putchar ('-'), a = -a;
char ss[100]; int i = 0;
for (; a; ) ss[++ i] = a % 10 + '0', a /= 10;
for (; i; ) putchar (ss[i --]);
}
template<typename A, typename ...B>
inline void read(A &x, B &...y)
{
read(x); read(y...);
}
template<typename A, typename ...B>
inline void print(A &x, B &...y)
{
print(x); putchar(' '); print(y...);
}
template <typename T>
inline T lowbit(T x) { return x & (-x); }
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define per(i,j,k) for(int i=j;i>=k;i--)
#define clr(x) memset(x,0,sizeof(x))
const int N = 300010;
const int inf = 1e9 + 100;
int n, m, a[N];
int ans[N];
int val[N<<2], tag[N<<2];
int key[N<<2];
pair<int, int> vl[N];
vector<pair<int, int> > q[N];
#define ls x<<1
#define rs x<<1|1
void build(int x, int l, int r)
{
val[x] = tag[x] = inf;
key[x] = -1;
if (l == r) return;
int mid = (l+r) >> 1;
build(ls, l, mid);
build(rs, mid+1, r);
}
int querykey(int x, int l, int r, int L, int R)
{
if (r < L || R < l) return -1;
if (L <= l && r <= R) return key[x];
int mid = (l+r) >> 1;
return max(querykey(ls, l, mid, L, R),
querykey(rs, mid+1, r, L, R));
}
int queryval(int x, int l, int r, int p)
{
if (l == r) return val[x];
int mid = (l+r) >> 1;
if (p <= mid) return min(tag[x], queryval(ls, l, mid, p));
else return min(tag[x], queryval(rs, mid+1, r, p));
}
void updkey(int x, int l, int r, int p, int v)
{
key[x] = max(key[x], v);
if (l == r) return;
int mid = (l+r) >> 1;
if (p <= mid) updkey(ls, l, mid, p, v);
else updkey(rs, mid+1, r, p, v);
}
void updval(int x, int l, int r, int L, int R, int v)
{
if (r < L || R < l) return;
if (L <= l && r <= R)
{
tag[x] = min(tag[x], v);
val[x] = min(val[x], v);
return;
}
int mid = (l+r) >> 1;
updval(ls, l, mid, L, R, v);
updval(rs, mid+1, r, L, R, v);
val[x] = min(val[ls], val[rs]);
}
int find(int x, int y)
{
return lower_bound(vl+1, vl+1+n, make_pair(x, y)) - vl;
}
int main() {
read(n);
rep(i,1,n)
read(a[i]), vl[i] = make_pair(a[i], i);
sort(vl+1, vl+1+n);
read(m);
rep(i,1,m)
{
int l, r;
read(l, r);
q[r].push_back(make_pair(l, i));
}
build(1, 1, n);
rep(i,1,n)
{
int pos = find(a[i], i);
int del = inf;
while (1)
{
int x = find(a[i]+del+1, 0);
if (x <= pos+1) break;
x = querykey(1, 1, n, pos+1, x-1);
if (x == -1) break;
int d = a[x] - a[i];
updval(1, 1, n, 1, x, d);
if (d == 0) break;
del = d >> 1;
}
del = inf;
while (1)
{
int x = find(a[i]-del, 0);
if (x >= pos) break;
x = querykey(1, 1, n, x, pos-1);
if (x == -1) break;
int d = a[i] - a[x];
updval(1, 1, n, 1, x, d);
if (d == 0) break;
del = d >> 1;
}
updkey(1, 1, n, pos, i);
for (auto p : q[i])
ans[p.second] = queryval(1, 1, n, p.first);
}
rep(i,1,m) print(ans[i]), puts("");
return 0;
}