Codeforces 765F. Souvenirs

来源:互联网 发布:安装ubuntu系统 编辑:程序博客网 时间:2024/05/20 23:58

Artsem is on vacation and wants to buy souvenirs for his two teammates. There are n souvenir shops along the street. In i-th shop Artsem can buy one souvenir for ai dollars, and he cannot buy more than one souvenir in one shop. He doesn't want to introduce envy in his team, so he wants to buy two souvenirs with least possible difference in price.

Artsem has visited the shopping street m times. For some strange reason on the i-th day only shops with numbers from li to ri were operating (weird? yes it is, but have you ever tried to come up with a reasonable legend for a range query problem?). For each visit, Artsem wants to know the minimum possible difference in prices of two different souvenirs he can buy in the opened shops.

In other words, for each Artsem's visit you should find the minimum possible value of |as - at|where li ≤ s, t ≤ ris ≠ t.

Input

The first line contains an integer n (2 ≤ n ≤ 105).

The second line contains n space-separated integers a1, ..., an (0 ≤ ai ≤ 109).

The third line contains the number of queries m (1 ≤ m ≤ 3·105).

Next m lines describe the queries. i-th of these lines contains two space-separated integers liand ri denoting the range of shops working on i-th day (1 ≤ li < ri ≤ n).

Output

Print the answer to each query in a separate line.

Example
input
83 1 4 1 5 9 2 641 81 34 85 7
output
0113

Artsem is on vacation and wants to buy souvenirs for his two teammates. There are n souvenir shops along the street. In i-th shop Artsem can buy one souvenir for ai dollars, and he cannot buy more than one souvenir in one shop. He doesn't want to introduce envy in his team, so he wants to buy two souvenirs with least possible difference in price.

Artsem has visited the shopping street m times. For some strange reason on the i-th day only shops with numbers from li to ri were operating (weird? yes it is, but have you ever tried to come up with a reasonable legend for a range query problem?). For each visit, Artsem wants to know the minimum possible difference in prices of two different souvenirs he can buy in the opened shops.

In other words, for each Artsem's visit you should find the minimum possible value of |as - at| where li ≤ s, t ≤ ris ≠ t.

Input

The first line contains an integer n (2 ≤ n ≤ 105).

The second line contains n space-separated integers a1, ..., an (0 ≤ ai ≤ 109).

The third line contains the number of queries m (1 ≤ m ≤ 3·105).

Next m lines describe the queries. i-th of these lines contains two space-separated integers li and ri denoting the range of shops working on i-th day (1 ≤ li < ri ≤ n).

Output

Print the answer to each query in a separate line.

Example
input
83 1 4 1 5 9 2 641 81 34 85 7
output
0113

题意:给N个数,多次询问区间中min(abs(a[i]-a[j]))

题解:假老师的题解好神啊QAQ

莫队算法,假设当前处理l[i]在某一块[L,R]的询问

把询问按右端点排序,从右到左删除,从左到右加入一次记录f[i]表示从R加到i时的贡献

从右到左再删除,一边删除一边处理询问,暴力删除后加入即可

用了链表的一个trick写法

#include <bits/stdc++.h>using namespace std;typedef pair< int, int > pa;const int MAXN = 100010;const int MAXM = 320;const int INF = 1e9 + 7;inline int read(){int sc = 0; char ch = getchar();while( ch < '0' || ch > '9' ) ch = getchar();while( ch >= '0' && ch <= '9' ) sc = sc * 10 + ch - '0', ch = getchar();return sc;}struct Query{int l, r, id;bool operator < ( const Query &b ) const { return r < b.r; }};int n, m, a[MAXN], pre[MAXN], nxt[MAXN], block, sorted[MAXN], dp[MAXM][MAXN], ans[MAXN], f[MAXN];vector < Query > v[MAXM];pa p[MAXN];inline void clear(){for( int i = 1 ; i <= n ; i++ ) pre[ i ] = i - 1, nxt[ i ] = i + 1;pre[ n + 1 ] = n; nxt[ 0 ] = 1;}inline void del(int x){pre[ nxt[ x ] ] = pre[ x ];nxt[ pre[ x ] ] = nxt[ x ];}inline int ins(int x){int ret = INF, t;t = nxt[ x ];if( t <= n ) ret = min( ret, sorted[ t ] - sorted[ x ] );t = pre[ x ];if( t ) ret = min( ret, sorted[ x ] - sorted[ t ] );pre[ nxt[ x ] ] = x; nxt[ pre[ x ] ] = x;return ret;}int main(){n = read(); block = sqrt( n );for( int i = 1 ; i <= n ; i++ ) a[ i ] = read(), p[ i ] = make_pair( a[ i ], i );sort( p + 1, p + n + 1 );for( int i = 1 ; i <= n ; i++ ) dp[ 1 ][ i ] = INF;for( int i = 2 ; i < MAXM ; i++ )for( int j = 1 ; j + i - 1 <= n ; j++ )dp[ i ][ j ] = min( min( dp[ i - 1 ][ j ], dp[ i - 1 ][ j + 1 ] ), abs( a[ j ] - a[ j + i - 1 ] ) );for( int i = 1 ; i <= n ; i++ ) a[ i ] = lower_bound( p + 1, p + n + 1, make_pair( a[ i ], i ) ) - p;for( int i = 1 ; i <= n ; i++ ) sorted[ i ] = p[ i ].first;int m = read();for( int i = 1 ; i <= m ; i++ ){Query q;q.l = read(); q.r = read(); q.id = i;if( q.r - q.l + 1 < MAXM ) ans[ i ] = dp[ q.r - q.l + 1 ][ q.l ];else v[ q.l / block ].push_back( q );}for( int i = 0 ; i < MAXM ; i++ ){if( v[ i ].empty() ) continue;clear();int L = i * block, R = L + block - 1;for( int j = 1 ; j < R ; j++ ) del( a[ j ] );for( int j = n ; j > R ; j-- ) del( a[ j ] );f[ R ] = INF;for( int j = R + 1 ; j <= n ; j++ ) f[ j ] = min( f[ j - 1 ], ins( a[ j ] ) );for( int j = R - 1 ; j >= L ; j-- ) ins( a[ j ] );sort( v[ i ].begin(), v[ i ].end() );for( int j = v[ i ].size() - 1, k = n ; j >= 0 ; j-- ){Query q = v[ i ][ j ];while( k > q.r ) del( a[ k-- ] );int cur = f[ k ];for( int c = L ; c < R ; c++ ) del( a[ c ] );for( int c = R - 1 ; c >= q.l ; c-- ) cur = min( cur, ins( a[ c ] ) );for( int c = q.l - 1 ; c >= L ; c-- ) ins( a[ c ] );ans[ q.id ] = cur;}}for( int i = 1 ; i <= m ; i++ ) printf( "%d\n", ans[ i ] );} 

另一种线段树做法

我们将询问按r排序,每次动态加入一个点

在线段树每个节点维护这一段的有序序列,和这一段的答案

考虑加入a[r]时,会修改前面所有点作为左端点的答案

但是,我们发现,每个点作为左端点的答案,从左到右是递增的

否则,右边有一个更优的答案,查询的时候包含了右边,那么左边的答案事实上是没有用的

所以记录当前的最小答案d

先更新右边,再更新左边

如果当前加入的数x在这一段的前驱和后继与x的差都大于等于d,那么答案不优,结束更新

否则递归更新

这样复杂度应该是有保证的

考虑最坏的情况是更新到了最左边的端点

那么序列应该是a[1]=1,a[2]=n, a[i]=(a[i-1]+a[1])/2-1才会达到最坏情况

每次把值域减少一半,最多只有log次更新

#include <bits/stdc++.h>using namespace std;const int MAXN = 100010;const int INF = 1e9 + 7;inline int read(){int sc = 0; char ch = getchar();while( ch < '0' || ch > '9' ) ch = getchar();while( ch >= '0' && ch <= '9' ) sc = sc * 10 + ch - '0', ch = getchar();return sc;}int a[MAXN], n, m, ans[MAXN << 2];struct node{vector < int > v;int ans;}e[MAXN << 2];struct Query{int l, r, id;bool operator < ( const Query &b ) const { return r < b.r; }}q[MAXN << 2];inline void merge(vector < int > &a, vector < int > b, vector < int > c){int szb = b.size(), szc = c.size();int i = 0, j = 0;for( ; i < szb ; i++ ){while( j < szc && c[ j ] < b[ i ] ) a.push_back( c[ j++ ] );a.push_back( b[ i ] );}while( j < szc ) a.push_back( c[ j++ ] );return ;}inline void build(int x, int l, int r){e[ x ].ans = INF;if( l == r ){e[ x ].v.push_back( a[ l ] );return ;}int mid = l + r >> 1;build( x << 1, l, mid );build( x << 1 | 1, mid + 1, r );merge( e[ x ].v, e[ x << 1 ].v, e[ x << 1 | 1 ].v );for( int i = 1 ; i <= r - l ; i++ ) e[ x ].ans = min( e[ x ].ans, e[ x ].v[ i ] - e[ x ].v[ i - 1 ] );return ;}inline int query(int x, int l, int r, int ql, int qr){if( l == ql && r == qr ) return e[ x ].ans;int mid = l + r >> 1;if( qr <= mid ) return query( x << 1, l, mid, ql, qr );if( ql > mid ) return query( x << 1 | 1, mid + 1, r, ql, qr );return min( query( x << 1, l, mid, ql, mid ), query( x << 1 | 1, mid + 1, r, mid + 1, qr) ); }inline void modify(int x, int l, int r, int qr, int v, int &d){//printf( "%d %d %d %d %d %d\n", x, l, r, qr, v, d );if( l == r ){e[ x ].ans = min( e[ x ].ans, abs( v - e[ x ].v[ 0 ] ) );d = min( d, e[ x ].ans );return ;}int mid = l + r >> 1;vector < int > :: iterator it = lower_bound( e[ x ].v.begin(), e[ x ].v.end(), v );if( ( it == e[ x ].v.end() || *it >= v + d ) && ( it == e[ x ].v.begin() || *( it - 1 ) <= v - d ) ){d = min( d, query( x, l, r, l, qr ) );return ;}if( qr > mid )modify( x << 1 | 1, mid + 1, r, qr, v, d ),modify( x << 1, l, mid, mid, v, d );elsemodify( x << 1, l, mid, qr, v, d );e[ x ].ans = min( e[ x ].ans, min( e[ x << 1 ].ans, e[ x << 1 | 1 ].ans ) );}int main(){n = read();for( int i = 1 ; i <= n ; i++ ) a[ i ] = read();build( 1, 1, n );m = read();for( int i = 1 ; i <= m ; i++ ) q[ i ].l = read(), q[ i ].r = read(), q[ i ].id = i;sort( q + 1, q + m + 1 );int r = 1, d;for( int i = 1 ; i <= m ; i++ ){while( r < q[ i ].r ) d = INF, modify( 1, 1, n, r, a[ r + 1 ], d ), r++;ans[ q[ i ].id ] = query( 1, 1, n, q[ i ].l, q[ i ].r );}for( int i = 1 ; i <= m ; i++ ) printf( "%d\n", ans[ i ] );return 0;}



1 0
原创粉丝点击