因为最多只有200000个点,每个海报的高度都是1单位,所以可能被用到的高度就是min(h,n),然后记录每个点高度,利用线段树维护区间最大值,然后利用二分思想每次找到最靠上的广告位置,然后修改当前行的值.
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <iostream>
#define MAX 200007
using namespace std;
int h,w,n;
struct Node
{
int l,r,maxn;
}tree[MAX<<2];
void push_up ( int u )
{
tree[u].maxn = max ( tree[u<<1].maxn , tree[u<<1|1].maxn );
}
void build ( int u , int l , int r )
{
tree[u].l = l , tree[u].r = r;
tree[u].maxn = w;
if ( l == r ) return;
int mid = l + r >> 1;
build ( u<<1 , l , mid );
build ( u<<1|1 , mid+1 , r );
}
void update ( int u , int x , int v )
{
int l = tree[u].l , r = tree[u].r;
if ( l == r )
{
tree[u].maxn -= v;
return;
}
int mid = l + r >> 1;
if ( x > mid ) update ( u<<1|1 , x , v );
else update ( u<<1 , x , v );
push_up ( u );
}
int x;
void find ( int u , int v )
{
int l = tree[u].l , r = tree[u].r;
if ( l == r )
{
x = l;
return;
}
if ( v > tree[u].maxn ) return;
if ( v > tree[u<<1].maxn ) find ( u<<1|1 , v );
else find ( u<<1 , v );
}
int main ( )
{
int a;
while ( ~scanf ( "%d%d%d" , &h, &w, &n ) )
{
build ( 1 , 1 , min ( h , n+1 ) );
for ( int i = 0 ; i < n ; i++ )
{
scanf ( "%d" , &a );
x = -1;
find ( 1 , a );
printf ( "%d\n" , x );
if ( x != -1 ) update ( 1 , x , a );
}
}
}