HDU 2795 Billboard(线段树)

来源:互联网 发布:mac git 安装 编辑:程序博客网 时间:2024/05/29 17:05

题意:

有一个h*w的公告牌,h是高度,w是宽度,一个单位高度1为一行,然后会有一些公告贴上去,公告是1*wi大小的长纸条,优先贴在最上面并且最左边的位置,如果没有空间贴得下,就输出-1,可以的话,就输出所贴的位置(第几行)。

解析:

叶节点maxv[x]表示board的第x行还可以放置的长度,区间[a,b]表示第a行到b行中剩下空间最大的那一行是多少,如果要把长w的公告放入board时就是update,优先往左子树走(如果左子树的空间足够的话),一直走到叶节点,更新这个叶节点剩下的长度,然后再向上更新。

注意:

由于h最大为10^9,一开始时没注意,建树直接build(1,1,h),而开不了这么大的数组,其实n最大才20W,所以h组多也只需要用到20W,只需要取 h = min(h,n) 即可。

还有这题的数据有变动数据量加大了,所以在输入时我选择了用输入外挂,并在查询时剪枝(如果已经找到答案,直接return)。

my code

#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>#include <cstdlib>using namespace std;typedef long long ll;const int INF = 0x3f3f3f3f;const int N = 2e5 + 10;int maxv[N << 2];int len, ans;int h, w, n;inline void read(int &x) {    int flag = 0;    x = 0;    char c = getchar();    if(c == '-')        flag = 1;    while(c < '0' || c > '9') {        if(c == '-')            flag = 1;        c = getchar();    }    while(c >= '0' && c <= '9')        x = x * 10 + c - '0', c = getchar();    if(flag) x = -x;}void build(int o, int L, int R) {    if(L == R) {        maxv[o] = w;        return ;    }    int M = (L + R)/2;    build(o*2, L, M);    build(o*2+1, M+1, R);    maxv[o] = max(maxv[o*2], maxv[o*2+1]);}void query(int o, int L, int R) {    if(L == R && !ans) {        maxv[o] -= len;        ans = L;        return;    }    int M = (L+R) / 2;    if(ans) return;    if(maxv[o*2] >= len) {        query(o*2, L, M);        maxv[o] = max(maxv[o*2], maxv[o*2+1]);    }else if(maxv[o*2+1] >= len) {        query(o*2+1, M+1, R);        maxv[o] = max(maxv[o*2], maxv[o*2+1]);    }}int main() {    while(scanf("%d%d%d", &h, &w, &n) != EOF) {        h = min(n, h);        build(1, 1, h);        for(int i = 1; i <= n; i++) {            read(len);            if(len > maxv[1])                puts("-1");            else {                ans = 0;                query(1, 1, h);                printf("%d\n", ans);            }        }    }    return 0;}
0 0
原创粉丝点击