题目大意:有一个广告板,告诉我们尺寸(即高度宽度),我们要贴广告,广告的尺寸规定为1*w,我们每次从最左上面开始贴,当给出的广告不够贴时,移到下一行贴。输出当前广告贴在第几行。
题目连接:-> HDU 2795
思路大意:拿高度来当"线段"进行拆分,每次更新一下贴完之后所剩余的长度,并顺便输出所在行即可。
接下来计算一下充当 线段树的数组 的宽度:
这个题目中广告版的高度范围比较大,10^9的数量级,估算一下,我们的数组至少开到2^31,显然会爆掉。
我们仔细看题,会知道所给出的 广告贴纸 的数量不多。
因此,我们可以优化,当高度大于了广告贴纸的数目(因为每一个广告贴纸的高度为1),令广告版高度等于广告贴纸数。广告贴纸数才20万,也就是说这个数组最小可以开到2^19(524288), 就60w好了。
下面这个简单的程序用来计算一个用于充当线段树的数组的大小:
题目连接:-> HDU 2795
思路大意:拿高度来当"线段"进行拆分,每次更新一下贴完之后所剩余的长度,并顺便输出所在行即可。
接下来计算一下充当 线段树的数组 的宽度:
这个题目中广告版的高度范围比较大,10^9的数量级,估算一下,我们的数组至少开到2^31,显然会爆掉。
我们仔细看题,会知道所给出的 广告贴纸 的数量不多。
因此,我们可以优化,当高度大于了广告贴纸的数目(因为每一个广告贴纸的高度为1),令广告版高度等于广告贴纸数。广告贴纸数才20万,也就是说这个数组最小可以开到2^19(524288), 就60w好了。
// HDU 2795 Billboard -- 线段树的应用
//
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <math.h>
#include <algorithm>
#include <time.h>
using namespace std;
const int MAXN = 600000;
int remain[MAXN]; // 广告版 lth ~ rth 行中剩余的长度的最大值
int Max(int a,int b){return (a>b)?(a):(b);}
void BuildTree(int v, int l, int r,int sub){// 值 左 右 数组下标
remain[sub] = v;
if (l == r) return;
int m = (l + r) >> 1;
BuildTree(v, l, m, sub << 1);
BuildTree(v, m+1, r, (sub<<1) + 1);
}
int UpdateTree(int v, int l, int r, int sub){
if (v > remain[sub] ) return -1;
if (l == r ){
remain[sub] -= v;
return l;
}
int m = (l + r) >> 1, res;
if (v <= remain[sub<<1])//判断进入左边还是右边,默认优先进入左边
res = UpdateTree(v , l , m , sub<<1);
else
res = UpdateTree(v , m + 1 , r , (sub<<1) + 1);
//更新当前节点的剩余长度 取两子节点的最大值
remain[sub] = Max(remain[sub<<1],remain[(sub<<1)+1]);
return res;
}
int main(){
int h,w,n;
while(cin >> h >> w >> n){
if(h > n) h = n;
BuildTree(w , 1 , h , 1) ;
while(n--){
int wi;
scanf("%d",&wi);
int res = UpdateTree(wi , 1 , h , 1);
printf("%d\n",res);
}
}
return 0;
}
下面这个简单的程序用来计算一个用于充当线段树的数组的大小:
#include <iostream>
#include <math.h>
using namespace std;
int main()
{
int n;
while(cin >> n){
int i = 1;
while(n > 1 && ++i) // 计算 1~n 建立线段树的深度输出为 2的深度次方
n = (n & 1)?(n / 2 + 1):(n / 2);
cout << pow(2.0,i*1.0) << endl;
}
return 0;
}