HDU2795(看似不是线段树的线段树)(一)

题目链接:hdu2795

这道题数据量太大,要是一般的暴力简单遍历,结果是 Time Limit Exceeded(我试过)。

由于 109 太大了,无法用定义长度为h(广告牌的高)的数组,于是看了看输入,只有200000组数据,就是说最多放200000行公告,于是可以把200000作为数组长度。

没有用线段树的超时代码

没有用线段树代码,超时

/***
 * hdu2795
 * 来来来,暴力一下怎么样??
 * Time Limit Exceeded
 */

#include<iostream>
#include<string>
#include<cstdio>
#include<algorithm>

using namespace std;

const int mmax = 200002;

int val[mmax];
int board[mmax];
int main()
{
    int h, w, n;
    while(scanf("%d%d%d",&h, &w, &n) == 3)
    {
        memset(val, 0, sizeof(val));
        memset(board, 0, sizeof(board));
        for(int i = 1; i <= n; i++)
            scanf("%d", &val[i]);

        for(int i = 1; i <= n; i++)
        {
            int j;
            for(j = 1; j <= h; j++)
            {
                if(w-board[j] < val[i])
                    continue;
                board[j] += val[i];
                printf("%d\n", j);
                break;
            }
            if(j == h+1)
                printf("-1\n");
        }
    }
}

用了线段树的AC代码

关于-1的情况可以在根结点处理,如果在函数中(我用的叫做query()函数)处理,可能导致wa。

建树的大小是有讲究的, if(h > n) h = n; build(1, 1, h); 这样做可以防止建树过大。

用了线段树代码,ac

/***
 * 线段树第三弹
 * 看似和区间没啥关系的线段树
 * ac
 */

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;
#define lc (d<<1)
#define rc (d<<1|1)
#define mid (l+r>>1)
const int mmax = 200002;

int val[mmax];
struct tree
{
    int v;
}tr[mmax<<2];//既然用了线段树,虽然结构体只有一个int v,但还是用结构体而不用数组

//建树,当然你可以直接memset(tr, 0, sizeof(tr));
void build(int d, int l, int r)
{
    if(l == r)
    {
        tr[d].v = 0;
        return;
    }
    build(lc, l, mid);
    build(rc, mid+1, r);
    tr[d].v = 0;
}

void query(int d, int l, int r, int w , int x)
{
    if(l == r)
    {
        tr[d].v += x;//注意要+=
        printf("%d\n", l);
        return;
    }
    if(tr[lc].v + x <= w)//必须先左后右
    {
        query(lc, l, mid, w, x);
    }
    else
    {
        query(rc, mid+1, r, w, x);
    }
    tr[d].v = min(tr[lc].v, tr[rc].v);
}

int main()
{
    int h, w, n;
    while(scanf("%d%d%d", &h, &w, &n) == 3)
    {
        for(int i = 1; i <= n; i++)
        {
            scanf("%d", &val[i]);
        }

        if(h > n) h = n;//优化
        build(1, 1, h);

        for(int i = 1; i <= n; i++)
        {
            //很妙的预先判断,把-1的情况完美处理
            if(tr[1].v + val[i] > w)
            {
                printf("-1\n");
                continue;
            }
            query(1, 1, h, w, val[i]);
        }
    }

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值