您的位置:首页 > 其它

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]所覆盖的区间范围

#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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: