【解题报告】 HDU 2795 Billboard -- 线段树的应用

来源:互联网 发布:深圳找工作知乎 编辑:程序博客网 时间:2024/06/06 03:23
题目大意:有一个广告板,告诉我们尺寸(即高度宽度),我们要贴广告,广告的尺寸规定为1*w,我们每次从最左上面开始贴,当给出的广告不够贴时,移到下一行贴。输出当前广告贴在第几行。
题目连接:->  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);elseres = 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;}

原创粉丝点击