线段树单点更新
题意:
一个广告板,知道它的长和宽,现在有N条信息需要在板上显示,每天信息都有自己的宽度,长度都为1。现在问你每条信息在哪个位置。
思路:
利用线段树,将有多少条信息或者高度作为线段树的最大区间,然后题目中说明要如果不能放在最上边(topmost),那么就放在最左边的上边(leftmost)。现在以样例为准来说明,依据样例数据,那么线段树的区间为1~3,那么首先宽度为2的进来,然后放在1的位置,宽度为4的进来放在2的位置(因为1位置所剩宽度不够)。。。第一个宽度为3的进来,发现1位置还剩下3的宽度刚好够,于是把这条信息放在这里面。。。最后一个宽度为3的进来发现有问题,这时候没有空间可以用来放置了,于是输出-1.
注意点:
输入输出都要用格式化输入输出,还有就是如果是长度大于信息条数,那么按照信息条数作为线段树最大区间,反之。
#include<iostream>
#include<fstream>
#include<string>
using namespace std;
int H, W, N, T;
#define maxn 200100
#define Lchild rt<<1,L,m
#define Rchild rt<<1|1,m+1,R
int tree[maxn * 4];
void push_up(int rt)
{
tree[rt] = tree[rt << 1] > tree[rt << 1 | 1] ? tree[rt << 1] : tree[rt << 1 | 1];
}
void build(int rt = 1, int L = 1, int R = T)
{
if (L == R)
{
tree[rt] = W;
return;
}
int m = (L + R) >> 1;
build(Lchild);
build(Rchild);
push_up(rt);
}
int update(int w, int rt = 1, int L = 1, int R = T)
{
if (tree[rt] < w)
return -1;
if (L == R&&tree[rt] >= w)
{
tree[rt] -= w;
return L;
}
int m = (L + R) >> 1;
int ret = -1;
if (tree[rt << 1] >= w)
ret = update(w, rt << 1, L, m);
else if (tree[rt << 1 | 1] >= w)
ret = update(w, rt << 1 | 1, m + 1, R);
push_up(rt);
return ret;
}
int main()
{
while (~scanf_s("%d%d%d", &H, &W, &N))
{
T = N > H ? H : N;
build();
int n;
for (int i = 1; i <= N; i++)
{
scanf_s("%d", &n);
printf("%d\n", update(n));
}
}
return 0;
}