Codeforces 765F. Souvenirs
来源:互联网 发布:安装ubuntu系统 编辑:程序博客网 时间:2024/05/20 23:58
题意:给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
- Codeforces 765F. Souvenirs
- 【Codeforces Round #397】Codeforces 765F Souvenirs【解法一】
- 【Codeforces Round #397】Codeforces 765F Souvenirs【解法二】
- Codeforces Round #397 F Souvenirs(线段树)
- Codeforces Round #397 Problem F. Souvenirs 解题报告
- Codeforces Round #397 F. Souvenirs(线段树,离线)
- Codeforces Gym 100753J Souvenirs
- Codeforces 808E Selling Souvenirs 题解
- Codeforces 808E Selling Souvenirs【思维+Dp】
- Codeforces GYM 100753J: Souvenirs 题解
- [杂题 贪心] Codeforces 808E. Selling Souvenirs
- Codeforces 659F F
- 01背包 Educational Codeforces Round 21 E. Selling Souvenirs
- codeforces Round 21 808E. Selling Souvenirs 【dp好题】
- CodeForces 808E Selling Souvenirs(三分法/单调优化dp)
- 【codeforces 808E】【Selling Souvenirs】【贪心】【动态规划】
- Educational Codeforces Round 21 E. Selling Souvenirs 三分, 贪心
- Codeforces 234 F. Fence
- 把view保存成bitmap,保存bitmap到sd卡
- BZOJ4246: 两个人的星座
- uC/OS-ii系统内核理解(三)_初始化调用函数
- 文件特殊权限:SUID,SGID和SBIT
- ReactJS component names must begin with capital letters?!
- Codeforces 765F. Souvenirs
- 003_Windows程序设计--窗口与消息
- C++静态链接库
- 类加载机制
- QQ第三方登录实例demo(QQSDK包优化)
- 二十四节气的计算方法
- Spring Boot 静态资源处理
- Poj 1094 Sorting It All Out 【拓扑排序】
- Redis常用的命令(一)-------启动、配置等