题意:
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]=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[n].c = a[n].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;
}