解题思路:这道题很难想到是用线段树,确实转化的很巧妙
实际上,我们只需要利用线段树(记录1-h)维护哪个位置的剩余空间最大即可,即1,2,......,h是线段树的叶子节点,我们每次要找的就是叶子节点的剩余空间的最大值,只要能够想到这里就很容易啦。。另外如果h>n的话,就令h=n,否则就是类似于位置多而要贴上去的砖少,这样就不合题目意思了。。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int maxn = 200005; struct seg { int l,r,value,id; }tree[maxn<<2]; int h,w,n; void build(int l,int r,int u) { tree[u].l = l; tree[u].r = r; tree[u].value = w; tree[u].id = l; if(l == r) return; int mid = (l + r) >> 1; build(l,mid,2*u); build(mid+1,r,2*u+1); } void update(int l,int r,int v,int u) { if(tree[u].l >= l && tree[u].r <= r){ tree[u].value -= v; return; } int mid = (tree[u].l + tree[u].r) >> 1; if(l <= mid) update(l,r,v,2*u); if(r > mid) update(l,r,v,2*u+1); if(tree[2*u].value >= tree[2*u+1].value){ tree[u].value = tree[2*u].value; tree[u].id = tree[2*u].id; } else{ tree[u].value = tree[2*u+1].value; tree[u].id = tree[2*u+1].id; } } int query(int v,int u) { if(tree[u].value < v) return -1; if(tree[u].l == tree[u].r) return tree[u].id; if(tree[2*u].value >= v) return query(v,2*u); else return query(v,2*u+1); } int main() { int x; while(scanf("%d%d%d",&h,&w,&n)!=EOF) { if(h > n) h = n; build(1,h,1); for(int i = 1; i <= n; i++){ scanf("%d",&x); int tmp = query(x,1); if(tmp != -1){ printf("%d\n",tmp); update(tmp,tmp,x,1); } else printf("-1\n"); } } return 0; }