您的位置:首页 > 其它

HDU2795 线段树 单点更新 区间最大值

2017-08-09 17:30 471 查看
题意:有h*w的告示板, 每张通知的规格为1*wi, 通知张贴的位置优先选最上端的位置, 其次选最左的位置, 求每张通知张贴在第几行?

思路:记录每一行所剩长度, 运用线段树维护区间最大值。左子树值大于wi, 则查询左子树, 否则查询右子树。

反思:

1. 思维不够缜密: 刚开始的想法和正解是相同的, 但考虑到h的范围为1e9, 继而否定了自己的想法。 然而忽略了(所需要用到的)h <= n这一个隐藏条件。

2. 未解之谜:将33行注释掉, 而改成现在版本, 就AC了, 没想清楚原因。

#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
const int MAXN = 200000+10;
int ma[MAXN << 2];
int h, w, n;
void PushUp(int rt)
{
ma[rt] = max(ma[rt << 1], ma[rt << 1 | 1]);
return;
}
void Build(int l, int r, int rt)
{
if(l == r)
{
ma[rt] = w;
return;
}
int m = (l + r) >> 1;
Build(l, m, rt << 1);
Build(m + 1, r, rt << 1 | 1);
PushUp(rt);
return;
}
int Query(int w, int l, int r, int rt)
{
if(l == r)
{
return l;
}
int m = (l + r) >> 1;
//if(ma[rt] < w) return -1;
if(ma[rt << 1] >= w) Query(w, l, m, rt << 1);
else Query(w, m + 1, r, rt << 1 | 1);
}
void Update(int L, int w, int l, int r, int rt)
{
if(l == r)
{
ma[rt] -= w;
return;
}
int m = (l + r) >> 1;
if(L <= m) Update(L, w, l, m, rt << 1);
else Update(L, w, m + 1, r, rt << 1 | 1);
PushUp(rt);
return;
}
int main()
{
while(~scanf("%d%d%d", &h, &w, &n))
{
h = min(h, n);
Build(1, h, 1);
int ww;
for(int i = 0; i < n; i++)
{
cin >> ww;
if(ma[1] < ww) {printf("-1\n"); continue;}
int ans = Query(ww, 1, h, 1);
Update(ans, ww, 1, h, 1);
printf("%d\n", ans);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  ACM