Billboard
Time Limit: 20000/8000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 27455 Accepted Submission(s): 11200
翻译:
你有一张 h*w 的木板(长为h,宽为w) 现在每次给你一张 1 * wi 的纸,(长为1,宽为wi),横着贴,问你贴得上吗? 贴的上就输出行数,并把它贴上,贴不上就输出 -1 ,并且不贴它。
贴的时候要尽量靠上靠左贴,也就是行数越小越好,行数相同,就越左越好。
解题思路:
首先,这道题不是思维题(不知道谁说的思维题,害得我不敢做 Ta -_- )
其次,我们应该想到既然 要 求行数,我们不妨把行数作为我们的区间,进行线段树操作。
然后,我们发现这个行数太大了,10的9次方? 我的妈呀
接着,我们看到 n<=200000 (好像经常看到的样子啊~原来是线段树的套路数据范围啊)
就想,一共200000 张纸,就像每行贴一张也顶多只要 200000 (20 W)行,
多余的咋们用不到啊,谁叫Ta要往上贴,取小就好
于是,我们良好地确定了算法,线段树来也——
我们只需要知道区间上的 最大值 即可 。
(查询区间最大值,若 有满足的 则减去这张纸的wide,用个全局变量保存答案-行数)
左儿子的编号小 (行数小 (长) [ l,r ] 代表 l 行到 r 行) 所以我们走左子树就好
PS:(如果你 WA 了)
确定行数的时候不能取 min ,详见代码 注释掉的 第54 行 ,为什么?
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
inline void wprint(int x){
if (x>9) wprint(x/10);
putchar(x%10+'0');
}
inline void print(int x){
if (x<0) x=-x,putchar('-');
wprint(x);
putchar('\n');
}
inline int wread(){
char c(getchar());int wans(0),flag(1);
while (c<'0' || c>'9') {if (c=='-') flag=-1;c=getchar();}
while (c>='0' && c<='9' ){wans=wans*10+c-'0';c=getchar();}
return wans*=flag;
}
inline int max (int a,int b){return a>b?a:b;}
inline int min (int a,int b){return a<b?a:b;}
struct node{int l,r,maxn;}e[800006];
int h,w,n,T,ans;
void make_tre (int a,int l,int r){
e[a].l=l; e[a].r=r; e[a].maxn=w; //一开始都有w这么宽,到后面贴上了就减去宽度
if (l==r) {return ;}
int mid(l+r >>1),lson(a<<1), rson(a<<1|1);
make_tre (lson,l,mid);make_tre (rson,mid+1,r);
}
void change_max (int a,int wid){
if (e[a].l==e[a].r){e[a].maxn-=wid; ans=e[a].l; return ;}
int lson(a<<1),rson(a<<1|1);
if (e[lson].maxn>=wid) //看左子树行不行,行就走左子树
change_max (lson,wid);
else if (e[rson].maxn>=wid) //左子树不行,看右子树行不行
change_max (rson,wid);
else {ans=-1; return ;} //左右子树 都没有满足条件的 宽度 ,就返回-1
e[a].maxn = max(e[lson].maxn, e[rson].maxn);
}
int main (){
while (~scanf ("%d%d%d",&h,&w,&n)){
// T=min(k,n);
T=h;
if(h>200000) T=200000;
make_tre(1,1,T);
while (n--){
ans=0; // 保存答案
int wid(wread());
change_max (1,wid);
print(ans);
}
}
return 0;
}