思路: 线段树+单点更新
分析:
1 题目的意思是给定一个h*w的广告牌h为高,w为宽,现在有n个高为1宽为wi的小广告要放上去,原则是最先放最上面和最左边的位置
2 题目的h和w的最大值为10^9,但是n最大为200000。所以我们可以知道最多用掉的广告牌就是x = min(n , h),而这个值就是200000,所以我们可以把每一行作为一个点来利用线段树,线段树的区间[i , j]存储的是第i行到第j行的最大的剩余空间,那么我们只要每一次去查找整个区间[1 , x] ,然后我们要优先的考虑左子树,这样就能够满足要求的条件了
代码;
/************************************************ * By: chenguolin * * Date: 2013-09-02 * * Address: http://blog.csdn.net/chenguolinblog * ************************************************/ #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #define Lson(x) (x<<1) #define Rson(x) (Lson(x)|1) #define Mid(x,y) ((x+y)>>1) #define Sum(x,y) (x+y) typedef long long int64; const int MAXN = 200010; int h , w , n; struct Node{ int left; int right; int64 maxVal; }; Node node[4*MAXN]; void push_up(int pos){ node[pos].maxVal = max(node[Lson(pos)].maxVal , node[Rson(pos)].maxVal); } void init(int left , int right , int pos){ node[pos].left = left; node[pos].right = right; if(node[pos].left == node[pos].right){ node[pos].maxVal = w; return; } int mid = Mid(left , right); init(left , mid , Lson(pos)); init(mid+1 , right , Rson(pos)); push_up(pos); } void update(int index , int val , int pos){ if(node[pos].left == node[pos].right){ node[pos].maxVal -= val; return; } int mid = Mid(node[pos].left , node[pos].right); if(index <= mid) update(index , val , Lson(pos)); else update(index , val , Rson(pos)); push_up(pos); } int query(int left , int right , int val , int pos){ if(node[pos].maxVal < val) return -1; if(left == right) return node[pos].maxVal >= val ? left : -1; int mid = Mid(left , right); int ans = query(left , mid , val , Lson(pos)); if(ans == -1) return query(mid+1 , right , val , Rson(pos)); else return ans; } void input(){ int m = n; int i , x; n = min(n , h); init(1 , n , 1); while(m--){ scanf("%d" , &x); int ans = query(1 , n , x , 1); printf("%d\n" , ans); if(ans != -1) update(ans , x , 1); } } int main(){ while(scanf("%d%d%d" , &h , &w , &n) != EOF) input(); return 0; }