题意:一块宽w高h的板,有n张纸条,线条高度为1,第i张纸条的宽度为wi,将这n张纸条按顺序从上到下,从左到右贴在那块板上,输出各纸条贴在了第几行,无法贴的输出-1。 (1 <= h,w <= 10^9; 1 <= n <= 200,000)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2795
——>>线段树过,将块的高度作为线段树区间,维护各结点对应的最大容纳量就好。开始建树时我直接来了个build(1, 1, h),结果是RE,我想数组没开小,又不用指针,怎么会是RE?于是换了建树方法,直接把4*maxn个结点全部赋为w,结果还是RE,我想会不会是太大了,于是来个二分测试,submit了几十次,测出了给前400021个结点赋w时,返回的都是WA,给400022以上个结点赋w时,返回的都是RE,my god!这怎么过?再看一下别人的代码,发现有个if(h > n) h = n;东东,顿悟了!h <= 10^9,如果测试数据中来个h = 10^9,查询线段树query(1, 1, h)是一定RE的!!!如果板的高度h大于纸条的张数n,即使n张纸条全部贴下,最多就占n行,即使此时h = 10^9,如果板的高度h小于等于纸条的张数n,线段树区间的右端只能是h。所以不能直接用h或者n来做线段树的右端,应选h,但当if(h > n) h = n。
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 200000 + 10;
int maxv[maxn<<2], w, wi;
int query(int o, int L, int R) //查询&更新
{
if(maxv[o] < wi) return -1; //不满足
if(L == R && maxv[o] >= wi) //叶子结点满足时,更新返回
{
maxv[o] -= wi;
return L;
}
int M = L + (R - L) / 2, ans;
if(maxv[2*o] >= wi) ans = query(2*o, L, M); //先左后右
else ans = query(2*o+1, M+1, R);
maxv[o] = max(maxv[2*o], maxv[2*o+1]); //更新
return ans;
}
void build(int o, int L, int R) //建树
{
if(L == R)
{
maxv[o] = w;
return;
}
int M = L + (R - L) / 2;
build(2*o, L, M);
build(2*o+1, M+1, R);
maxv[o] = w;
}
int main()
{
int h, n, i;
while(~scanf("%d%d%d", &h, &w, &n))
{
if(h > n) h = n; //这句千万别少!!!直接用h来建树RE,直接用n建树WA
build(1, 1, h);
for(i = 1; i <= n; i++)
{
scanf("%d", &wi);
printf("%d\n", query(1, 1, h));
}
}
return 0;
}
本文介绍了一个利用线段树解决纸条贴板问题的方法,通过合理设置线段树的高度避免运行时错误,并提供了完整的代码实现。
581

被折叠的 条评论
为什么被折叠?



