题意
给你一个广告牌的长度和宽度,和要贴的广告数。每条广告的长度为 1 ,输入n条广告的高。输出广告所在的行数。所有的广告都靠左贴。
思路
以行数h来建树,每一个叶子结点代表一行,以数组node存放剩余宽度,初始化为广告牌的宽度。减去每次用掉的宽度,更新剩余宽度的最大值。
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=524288+10;
int node[maxn]; // 存放区间最大值(最宽的哪一行)
int h,w,n;
void bulid(int l,int r,int rt)
{
node[rt]=w; // 把每一个区间初始化为 剩余的宽度,一开始没贴广告所以每个区间剩余宽度等于广告牌的宽
if(l==r)
return ;
int m=(l+r)>>1;
bulid(l,m,rt<<1);
bulid(m+1,r,rt<<1|1);
}
int query(int x,int l,int r,int rt)
{
if(l==r) // 广告只能贴在叶子结点区间上 每一个叶子结点代表一行
{
node[rt]-=x;
return l; // 这个广告贴在第几行(叶子节点)
}
int m=(l+r)>>1;
int res;
if(node[rt<<1]>=x) // 如果左子树的 剩余最大宽度 大于需要的宽度就遍历左子树,否则就遍历右子树
//正好符合先贴左边的要求
res=query(x,l,m,rt<<1);
else
res=query(x,m+1,r,rt<<1|1);
node[rt]=max(node[rt<<1],node[rt<<1|1]); // 更新剩余最大宽度
return res;
}
int main()
{
int x;
while(~scanf("%d%d%d",&h,&w,&n))
{
if(h>n)
h=n; //最多输入n行数据,当h>n时,建n行就够了
bulid(1,h,1); // 以行数h建树
for(int i=0;i<n;i++)
{
scanf("%d",&x);
if(x>node[1]) //node[1]为所有区间当中的最大值
printf("-1\n");
else
printf("%d\n",query(x,1,h,1));
}
}
return 0;
}
这道题如果不是挂在线段树专题,我肯定不会想到用线段树。。。