FOJ 2014 4月月赛 D多米诺骨牌
2014-04-13 20:53
337 查看
题意:
n个多米诺骨牌,排成一排,每个牌都有一个位置xi和高度hi
求每个牌往右推,能推倒多少个牌。(第i个牌倒下后位置在[xi+1,xi+hi-1]的牌都要倒下)
刚看到以为是单调栈,写到一半改成dp,dp写完后才发现思路是错的。
因为一个牌子推倒后是把区间[xi+1,xi+hi-1]的所有牌子都推倒,而不是只推倒下一个牌子
最后用线段树搞了,
先按xi排序
首先每个牌子能推倒的牌子都是连续的,比如第一个牌子如果不可能把第三个牌子推倒了,却没有推倒第二个牌子。
假设每个牌子能推倒的牌子的区间是c[i]~d[i],然后c[i]就一定等于i,d[i]就等于第i个牌子开始向右倒后最后一个倒的牌子。
所以每个牌子倒后能推倒的牌子的个数为d[i]-c[i]+1,
问题就转化为怎么求d[i]
对于一个牌子,如果在[xi+1,xi+hi-1]里面没有牌子的话,d[i]就等于i了,
假设有一个牌子j的话,d[i]=d[j];
如果覆盖了第i+1,i+2...k个牌子的话,d[i] = max( d[i+1], d[i+2],...d[k] );
所以果断用线段树搞
d
=n;
所以就可以从右向左求出d[i];
再把d[i]插入线段树中
有一个二分查找求出[xi+1,xi+hi-1]所覆盖的区间范围
n个多米诺骨牌,排成一排,每个牌都有一个位置xi和高度hi
求每个牌往右推,能推倒多少个牌。(第i个牌倒下后位置在[xi+1,xi+hi-1]的牌都要倒下)
刚看到以为是单调栈,写到一半改成dp,dp写完后才发现思路是错的。
因为一个牌子推倒后是把区间[xi+1,xi+hi-1]的所有牌子都推倒,而不是只推倒下一个牌子
最后用线段树搞了,
先按xi排序
首先每个牌子能推倒的牌子都是连续的,比如第一个牌子如果不可能把第三个牌子推倒了,却没有推倒第二个牌子。
假设每个牌子能推倒的牌子的区间是c[i]~d[i],然后c[i]就一定等于i,d[i]就等于第i个牌子开始向右倒后最后一个倒的牌子。
所以每个牌子倒后能推倒的牌子的个数为d[i]-c[i]+1,
问题就转化为怎么求d[i]
对于一个牌子,如果在[xi+1,xi+hi-1]里面没有牌子的话,d[i]就等于i了,
假设有一个牌子j的话,d[i]=d[j];
如果覆盖了第i+1,i+2...k个牌子的话,d[i] = max( d[i+1], d[i+2],...d[k] );
所以果断用线段树搞
d
=n;
所以就可以从右向左求出d[i];
再把d[i]插入线段树中
有一个二分查找求出[xi+1,xi+hi-1]所覆盖的区间范围
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<set> #include<map> #include<queue> #include<vector> #include<cstdlib> #include<stack> using namespace std; #define inf 0x3f3f3f3f #define eps 1e-7 #define LL long long #define ULL unsigned long long #define MP make_pair #define pb push_back #define ls ( i << 1 ) #define rs ( ls | 1 ) #define md ( ( ll[i] + rr[i] ) >> 1 ) #define PI acos( -1.0 ) #define mxn 400030 struct node { int x, h, num; int c, d; bool operator < ( const node &b ) const { return x < b.x; } }a[mxn]; int n; int ll[mxn], rr[mxn], mx[mxn]; bool cmp( node x, node y ) { return x.num < y.num; } void read() { for( int i = 1; i <= n; ++i ) { scanf( "%d%d", &a[i].x, &a[i].h ); a[i].num = i; } sort( a + 1, a + n + 1 ); } void build( int l, int r, int i ) { ll[i] = l, rr[i] = r; mx[i] = 0; if( l == r ) { return ; } build( l, md, ls ), build( md + 1, r, rs ); } void update( int k, int v, int i ) { if( ll[i] == rr[i] ) { mx[i] = v; return; } if( k <= md ) update( k, v, ls ); else update( k, v, rs ); mx[i] = max( mx[ls], mx[rs] ); } int query( int l, int r, int i ) { if( ll[i] == l && rr[i] == r ) return mx[i]; if( r <= md ) return query( l, r, ls ); if( l > md ) return query( l, r, rs ); return max( query( l, md, ls ), query( md + 1, r, rs ) ); } int find( int head, int val ) { int tail = n + 1; while( head < tail - 1 ) { int mid = ( head + tail ) / 2; if( a[mid].x <= val ) head = mid; else tail = mid; } return head; } void solve() { build( 1, n, 1 ); a .c = a .d = n; update( n, n, 1 ); for( int i = n - 1; i >= 1; --i ) { int p = find( i, a[i].x + a[i].h - 1 ); if( p == i ) { a[i].c = a[i].d = i; update( i, i, 1 ); } else { int t = query( i + 1, p, 1 ); a[i].c = i, a[i].d = t; update( i, t, 1 ); } } sort( a + 1, a + n + 1, cmp ); for( int i = 1; i <= n; ++i ) printf( "%d%c", a[i].d - a[i].c + 1, i == n ? '\n' : ' ' ); } int main() { // freopen( "tt.txt", "r", stdin ); while( scanf( "%d", &n ) != EOF ) { read(); solve(); } return 0; }
相关文章推荐
- FOJ 有奖月赛 4月(校赛热身赛)D题 小茗的魔法阵
- 2014.4月问题种种
- 2014/4月金山WPS笔试
- FOJ2014 The Data
- XTU Monthly, April 2014(湘潭大学4月月赛)
- 2014/4月金山WPS笔试
- foj 2160 2014.4月赛
- 2014校园招聘之三(4月腾讯实习生笔试题)
- foj2014
- 【Good Bye 2014E】【贪心 单调栈+线段树】New Year Domino 至少增加多高长度的多米诺骨牌才可推x倒y
- 关于2014的开头
- SQL SERVER 2014 安装图解(含 SQL SERVER 2014 安装程序共享)
- SQL SERVER 2012/ 2014 分页,用 OFFSET,FETCH NEXT改写ROW_NUMBER的用法
- bzoj5154 [Tjoi2014]匹配(枚举+费用流)
- iOS应用国际化教程(2014版)
- 2014最后一天到2015新年第一天凌晨4加班中
- noip2014 解方程
- CS131 Computer Vision: Foundations and Applications (Fall 2014) Problem Set 0
- 2014-2015-1学期使用的教材
- SQL Server 2014 日志传送部署(7):日志传送故障转移和删除日志传送