#include<bits/stdc++.h>
using namespace std;
// Kích thước khối cho thuật toán chia căn
const int BLOCK_SIZE = 400;
// Số phần tử tối đa
const int MAXN = 3e5 + 5;
// Giá trị vô cùng lớn
const int INF = 1e9;
// Cấu trúc để lưu một truy vấn
struct Query {
int l, r; // [l, r] là đoạn truy vấn
int id; // ID ban đầu của truy vấn để trả về kết quả đúng thứ tự
};
// --- Biến toàn cục ---
int n, q; // Số phần tử của mảng và số lượng truy vấn
int original_array[MAXN]; // Mảng ban đầu
int sorted_values[MAXN]; // Mảng chứa các giá trị đã được sắp xếp
int rank_in_sorted[MAXN]; // rank_in_sorted[i] = vị trí của original_array[i] trong mảng đã sắp xếp
int ans[MAXN]; // Mảng lưu kết quả cho các truy vấn
// Mảng cho cấu trúc dữ liệu danh sách liên kết đôi (trên các giá trị đã sắp xếp)
int next_val[MAXN];
int prev_val[MAXN];
// Mảng DP: dp[len][start] = kết quả cho đoạn [start, start + len - 1]
int dp[BLOCK_SIZE + 5][MAXN];
// Mảng f: f[i] dùng để tính trước kết quả cho phần bên phải của block
int f[MAXN];
// Vector chứa các truy vấn được nhóm theo block
vector<Query> queries_by_block[MAXN / BLOCK_SIZE + 5];
// --- Hàm chức năng ---
// Hàm so sánh để sắp xếp các truy vấn trong một block
// Sắp xếp theo r giảm dần để tối ưu việc di chuyển con trỏ
bool compareQueries(const Query& a, const Query& b) {
return a.r > b.r;
}
// Hàm "thêm" một phần tử vào cấu trúc dữ liệu (danh sách liên kết đôi)
// và trả về chênh lệch nhỏ nhất mới được tạo ra
int addElement(int val_rank) {
int min_diff = INF;
// Chênh lệch với phần tử đứng trước nó trong dãy đã sắp xếp
if (prev_val[val_rank] >= 1) {
min_diff = min(min_diff, sorted_values[val_rank] - sorted_values[prev_val[val_rank]]);
}
// Chênh lệch với phần tử đứng sau nó trong dãy đã sắp xếp
if (next_val[val_rank] <= n) {
min_diff = min(min_diff, sorted_values[next_val[val_rank]] - sorted_values[val_rank]);
}
// Cập nhật con trỏ của các phần tử lân cận để trỏ đến phần tử vừa thêm
next_val[prev_val[val_rank]] = val_rank;
prev_val[next_val[val_rank]] = val_rank;
return min_diff;
}
// Hàm "xóa" một phần tử khỏi cấu trúc dữ liệu
void removeElement(int val_rank) {
// Nối phần tử trước và sau lại với nhau
next_val[prev_val[val_rank]] = next_val[val_rank];
prev_val[next_val[val_rank]] = prev_val[val_rank];
}
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
// --- Đọc dữ liệu và tiền xử lý ---
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> original_array[i];
sorted_values[i] = original_array[i];
}
// Sắp xếp các giá trị để tìm chênh lệch
sort(sorted_values + 1, sorted_values + n + 1);
// Thêm các giá trị biên để tránh xử lý các trường hợp đặc biệt
sorted_values[0] = -INF;
sorted_values[n + 1] = INF * 2;
// Map để xử lý các giá trị trùng lặp
// Gán cho mỗi phần tử original_array[i] một "rank" duy nhất trong mảng đã sắp xếp
map<int, int> duplicate_counter;
for (int i = 1; i <= n; i++) {
int base_rank = lower_bound(sorted_values + 1, sorted_values + n + 1, original_array[i]) - sorted_values;
rank_in_sorted[i] = base_rank + (duplicate_counter[base_rank]++);
}
// --- Đọc và phân loại truy vấn vào các block ---
cin >> q;
for (int i = 1; i <= q; i++) {
int l, r;
cin >> l >> r;
int block_id = (l - 1) / BLOCK_SIZE;
queries_by_block[block_id].push_back({l, r, i});
}
// Sắp xếp các truy vấn trong mỗi block
for (int i = 0; i <= n / BLOCK_SIZE; i++) {
sort(queries_by_block[i].begin(), queries_by_block[i].end(), compareQueries);
}
// --- Quy hoạch động cho các truy vấn ngắn ---
for (int len = 1; len <= BLOCK_SIZE; len++) {
if (len == 1) {
for (int i = 1; i <= n; i++) dp[len][i] = INF;
} else {
for (int i = 1; i <= n - len + 1; i++) {
// Kết quả cho đoạn dài `len` tại `i` được tính từ:
// 1. Kết quả của đoạn dài `len-1` tại `i`
// 2. Kết quả của đoạn dài `len-1` tại `i+1`
// 3. Chênh lệch giữa phần tử đầu và cuối của đoạn hiện tại
dp[len][i] = min({dp[len - 1][i], dp[len - 1][i + 1], abs(original_array[i] - original_array[i + len - 1])});
}
}
}
// --- Xử lý các truy vấn theo từng block ---
for (int block_id = 0; block_id * BLOCK_SIZE < n; block_id++) {
int block_start = block_id * BLOCK_SIZE + 1;
int block_end = min(n, (block_id + 1) * BLOCK_SIZE);
int current_r = n;
// Khởi tạo danh sách liên kết đôi cho toàn bộ dải giá trị
for (int j = 0; j <= n + 1; j++) {
prev_val[j] = j - 1;
next_val[j] = j + 1;
}
// Tạm thời "xóa" các phần tử không thuộc phạm vi [block_end, n]
// để chuẩn bị tính mảng f
for (int j = 1; j < block_end; j++) removeElement(rank_in_sorted[j]);
// Tính trước mảng f[i] = min_diff trong đoạn [block_end, i]
f[block_end] = INF;
for (int j = block_end + 1; j <= n; j++) {
f[j] = min(f[j - 1], addElement(rank_in_sorted[j]));
}
// Thêm lại các phần tử của block hiện tại để chuẩn bị xử lý truy vấn
for (int j = block_end - 1; j >= block_start; j--) {
addElement(rank_in_sorted[j]);
}
// Xử lý từng truy vấn trong block hiện tại
for (const auto& query : queries_by_block[block_id]) {
// Trường hợp 1: Truy vấn ngắn, đã có kết quả từ DP
if (query.r - query.l + 1 <= BLOCK_SIZE) {
ans[query.id] = dp[query.r - query.l + 1][query.l];
continue;
}
// Trường hợp 2: Truy vấn dài, l nằm trong block, r nằm ngoài
// Kết quả ban đầu là min_diff trong [block_end, query.r]
ans[query.id] = f[query.r];
// Di chuyển con trỏ `current_r` về `query.r`
// Xóa các phần tử từ (current_r, query.r] khỏi cấu trúc
while (current_r > query.r) {
removeElement(rank_in_sorted[current_r--]);
}
// Xóa tạm thời các phần tử bên trái của block
for (int j = block_start; j < block_end; j++) {
removeElement(rank_in_sorted[j]);
}
// Thêm các phần tử từ [query.l, block_end - 1] vào và cập nhật kết quả
for (int j = block_end - 1; j >= query.l; j--) {
ans[query.id] = min(ans[query.id], addElement(rank_in_sorted[j]));
}
// Khôi phục lại trạng thái cho các phần tử bên trái block cho truy vấn tiếp theo
for (int j = query.l - 1; j >= block_start; j--) {
addElement(rank_in_sorted[j]);
}
}
}
// --- In kết quả ---
for (int i = 1; i <= q; i++) {
cout << ans[i] << "\n";
}
return 0;
}