yijan
2020-06-11 09:27:24
考虑对于每一个右端点
那么如果我们离线下来询问,我们要求的
现在考虑我们把
首先,暴力修改的复杂度肯定有问题。但是可以发现,由于我们求答案是算后缀的最小值,事实上有些位置是没有必要修改的。
对于每个
必须 被修改?因为有些位置是可以不用被修改的。如下图:
如图,考虑
考虑加入的位置,如果在蓝色位置,明显我们必须得修改
否则,如果修改在紫色位置,我们可以直接修改
如果加入的点在
这样总修改的点数就是
但是如何修改呢?可以使用线段树。这里得先修改右区间再修改左区间,且如果修改当前区间的时候更新得到的答案不如之前修改过的某个位置,就直接跳过就好了。所以我们也需要对线段树每个区间维护有序的这个区间内的所有的数。
这样实际递归下去修改的就只有上文提到的 必须被修改的位置。复杂度就是
#include "iostream"
#include "algorithm"
#include "cstring"
#include "cstdio"
#include "cmath"
#include "vector"
#include "map"
#include "set"
#include "queue"
using namespace std;
#define MAXN 300006
//#define int long long
#define rep(i, a, b) for (int i = (a), i##end = (b); i <= i##end; ++i)
#define per(i, a, b) for (int i = (a), i##end = (b); i >= i##end; --i)
#define pii pair<int,int>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
#define eb emplace_back
#define vi vector<int>
#define all(x) (x).begin() , (x).end()
#define mem( a ) memset( a , 0 , sizeof a )
typedef long long ll;
int n , m;
int A[MAXN];
struct poi {
int l , r , idx;
} Q[MAXN] ;
bool cmp( const poi& a , const poi& b ) {
return a.r < b.r;
}
int T[MAXN << 2]; vi S[MAXN << 2];
inline void pu( int rt ) {
T[rt] = min( T[rt << 1] , T[rt << 1 | 1] );
}
void build( int rt , int l , int r ) {
rep( i , l , r ) S[rt].pb( A[i] );
sort( all( S[rt] ) );
T[rt] = 0x3f3f3f3f;
if( l == r ) return;
int m = l + r >> 1;
build( rt << 1 , l , m ) , build( rt << 1 | 1 , m + 1 , r );
pu( rt );
}
int cur;
void mdfy( int rt , int l , int r , int p , int x ) {
if( r <= p ) {
auto it = lower_bound( all( S[rt] ) , x );
if( it != S[rt].end() ) T[rt] = min( T[rt] , ( *it ) - x );
if( it != S[rt].begin() ) T[rt] = min( T[rt] , x - *( it - 1 ) );
if( T[rt] >= cur ) return;
}
if( l == r ) {
cur = min( cur , T[rt] );
return;
}
int m = l + r >> 1;
if( p > m ) mdfy( rt << 1 | 1 , m + 1 , r , p , x );
mdfy( rt << 1 , l , m , p , x );
pu( rt );
cur = min( cur , T[rt] );
}
int que( int rt , int l , int r , int L ) {
if( L <= l ) return T[rt];
int m = l + r >> 1;
if( L <= m ) return min( T[rt << 1 | 1] , que( rt << 1 , l , m , L ) );
else return que( rt << 1 | 1 , m + 1 , r , L );
}
int ans[MAXN];
void solve() {
cin >> n;
rep( i , 1 , n ) scanf("%d",A + i);
cin >> m;
rep( i , 1 , m )
scanf("%d%d",&Q[i].l,&Q[i].r) , Q[i].idx = i;
sort( Q + 1 , Q + 1 + m , cmp );
build( 1 , 1 , n );
int cc = 1;
while( Q[cc].r <= 1 ) ++ cc;
rep( i , 2 , n ) {
cur = 0x3f3f3f3f;
mdfy( 1 , 1 , n , i - 1 , A[i] );
while( Q[cc].r == i ) ans[Q[cc].idx] = que( 1 , 1 , n , Q[cc].l ) , ++ cc;
}
rep( i , 1 , m ) printf("%d\n",ans[i]);
}
signed main() {
// int T;cin >> T;while( T-- ) solve();
solve();
}