题目链接
Segment Tree, single-point update
题意
有一块h*w的告示板,要向上面贴一些广告,每张广告都想被贴得尽量靠顶端,然后再尽量靠左。现有n块尺寸分别是1*wi的广告(高度都为1)依次贴上去,问没张广告贴得位置。
分析
首先实际贴得行数肯定是min(h,n),开始没注意这个,被数据范围吓到了。然后这个问题只要记录每一行还剩下多少宽度,然后每贴一个广告就查找尽量靠左并且宽度大于等于它的。于是这就是一个单点更新的线段树,只不过查询的地方稍微改一下即可。
AC代码
//HDU 2795 Billboard
//AC 2016-10-16 15:13:32
//Segment tree
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cctype>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <set>
#include <string>
#include <map>
#include <queue>
#include <deque>
#include <list>
#include <sstream>
#include <stack>
using namespace std;
#define cls(x) memset(x,0,sizeof x)
#define inf(x) memset(x,0x3f,sizeof x)
#define neg(x) memset(x,-1,sizeof x)
#define ninf(x) memset(x,0xc0,sizeof x)
#define st0(x) memset(x,false,sizeof x)
#define st1(x) memset(x,true,sizeof x)
#define lowbit(x) x&(-x)
#define input(x) scanf("%d",&(x))
#define inputt(x,y) scanf("%d %d",&(x),&(y))
#define bug cout<<"here"<<endl;
//#pragma comment(linker, "/STACK:1024000000,1024000000")//stack expansion
//#define debug
const double PI=acos(-1.0);
const int INF=0x3f3f3f3f;//1061109567-2147483647
const long long LINF=0x3f3f3f3f3f3f3f3f;//4557430888798830399-9223372036854775807
const int maxn=200000+100;
int h,w,n;
/* 线段树 */
struct segNode
{
int left,right;//结点对应的区间端点
/*结点的性质*/
int remain;
};
struct segTree
{
segNode tree[maxn*3+10];
/* 线段树构造函数 */
void build(int x,int left,int right)
{
tree[x].left=left;
tree[x].right=right;
if(left==right)//只有一个元素时
{
tree[x].remain=w;//储存单个元素的性质
return;
}
/*递归构造子树*/
int mid=(left+right)>>1;
build(x<<1,left,mid);
build(x<<1|1,mid+1,right);
/* 回溯更新当前结点依赖于子节点的性质 */
tree[x].remain=w;
return;
}
/* 线段树区间查询 */
int querry(int x,int v)
{
if(tree[x].remain<v)
return -1;
if(tree[x].left==tree[x].right)
return tree[x].left;
if(tree[x<<1].remain>=v)
return querry(x<<1,v);
else if(tree[x<<1|1].remain>=v)
return querry(x<<1|1,v);
}
/* 单点更新 */
void change(int x,int pos,int v)
{
if(tree[x].left==pos&&tree[x].right==pos)//找到这个点
{
/* 更新内容 */
tree[x].remain-=v;
return;
}
int mid=(tree[x].left+tree[x].right)>>1;
if(pos<=mid)
change(x<<1,pos,v);
else
change(x<<1|1,pos,v);
/* 回溯更新 */
tree[x].remain=max(tree[x<<1].remain,tree[x<<1|1].remain);
return;
}
}billboard;
int main()
{
//ios::sync_with_stdio(false);
//cin.tie(0);
#ifdef debug
freopen("E:\Documents\code\input.txt","r",stdin);
freopen("E:\Documents\code\output.txt","w",stdout);
#endif
//IO
while(scanf("%d %d %d",&h,&w,&n)!=EOF)
{
int N=min(h,n);
billboard.build(1,1,N);
int ads=0,pos=0;
while(n--)
{
input(ads);
pos=billboard.querry(1,ads);
printf("%d
",pos);
if(pos!=-1)
billboard.change(1,pos,ads);
}
}
return 0;
}