题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=2795
题目大意:
给定一个h * w大小的黑板报,h为黑板报的高,w为黑板报的宽。现在要贴上很多张海报,每张海报的大小为1 * m,m就是输入的海报宽度。从左上贴起,每次从上到下看有没有足够的空间贴海报,有就贴上。给定一组输入表示海报的宽度,输出每个海报贴的高度位置,若没得贴就输出-1。
解题思路:
一开始根本不知道怎么用线段树,看了题解之后才知道其模型其实很简单,构建一个大小等于海报数量的线段树,即表明每张海报贴一行就是了。然后维护的就是线段树左右子树的最大长度,这也很好理解,比如要贴的海报大小为a,如果线段树第一个节点值大于等于a,那么说明在线段树中有那么一个节点的剩余宽度大于a,也就是这一行可以贴这张海报。如果线段树第一个节点值小于a,那么说明这个黑板报的最大剩余宽度不足a,明显没法贴了。所以其实分析之后就是一个维护左右子节点最大值的线段树而已。
代码:
1 #include <iostream> 2 #include <cmath> 3 #include <cstdio> 4 #include <cstring> 5 #include <map> 6 #include <vector> 7 #include <algorithm> 8 using namespace std; 9 10 #define ll long long 11 #define INF 0x3f3f3f3f 12 #define LL_INF 0x3f3f3f3f3f3f3f3f 13 #define lson l, m, rt << 1 14 #define rson m + 1, r, rt << 1|1 15 #define MAX 200200 16 17 int h, w; 18 int maxn[MAX << 2]; 19 20 void pushUp(int rt) 21 { 22 maxn[rt] = max(maxn[rt << 1], maxn[rt << 1|1]); 23 } 24 25 void build(int l, int r, int rt) 26 { 27 if (l == r) { 28 maxn[rt] = w; 29 return; 30 } 31 int m = (l + r) >> 1; 32 build(lson); 33 build(rson); 34 pushUp(rt); 35 } 36 37 int query(int c, int l, int r, int rt) 38 { 39 if (l == r) { 40 maxn[rt] -= c; 41 return l; 42 } 43 int m = (l + r) >> 1; 44 int res = maxn[rt << 1] >= c ? query(c, lson) : query(c, rson); 45 pushUp(rt); 46 return res; 47 } 48 49 int main() 50 { 51 //freopen("debug\in.txt", "r", stdin); 52 //freopen("CON", "w", stdout); 53 int i, j, k; 54 int n; 55 while (~scanf("%d%d%d", &h, &w, &n)) { 56 int right; 57 if (h > n) right = n; 58 else right = h; 59 build(1, right, 1); 60 int width; 61 while (n--) { 62 scanf("%d", &width); 63 if (maxn[1] < width) 64 printf("-1 "); 65 else 66 printf("%d ", query(width, 1, right, 1)); 67 } 68 } 69 return 0; 70 }