线段树专辑—— hdu 2795 Billboard

http://acm.hdu.edu.cn/showproblem.php?pid=2795

这题咋一看和线段树没啥关系似的。其实不然,非线段树不能解也!

将黑板报上每一行看做一个节点线段,黑板的宽度为其容量,这样,H行黑板就对应了H个叶子节点。H的范围为10^9,看起来很大不是吗?我们再看通知的数目n,n的数目小于等于200000,也就是说,就算每一行都放一个通知,最多也只需要200000行,可见H<=10^9,这个纯属吓人的嘛

为每个线段添加一个max_left域,表示该区间的最大剩余容量,采用先序遍历树的方式,在max_left>=(通知长度) 的情况下一直向下查找,知道找到根节点,这个便是答案!

另外要注意,n可能会大于H,建树时候取最小的!

View Code
 1 #include<iostream>
2 #include<string>
3 using namespace std;
4
5 struct node
6 {
7 int l;
8 int r;
9 __int64 left;
10 };
11
12 node tree[1000000];
13 __int64 H,W,n;
14
15 __int64 max(__int64 a,__int64 b)
16 {
17 return a>b?a:b;
18 }
19
20 void build(int i,int l,int r)
21 {
22 tree[i].l=l;
23 tree[i].r=r;
24 tree[i].left=W;
25 if(l==r)
26 {
27 return;
28 }
29 int mid=(l+r)>>1;
30 build(i<<1,l,mid);
31 build(i<<1|1,mid+1,r);
32 }
33
34 int ans;
35 void updata(int i,__int64 w)
36 {
37 if(tree[i].l>H)
38 return;
39 if(tree[i].left>=w)
40 {
41 if(tree[i].l==tree[i].r)
42 {
43 tree[i].left-=w;
44 ans=tree[i].l;
45 return;
46 }
47 if(tree[i<<1].left>=w)
48 updata(i<<1,w);
49 else if(tree[i<<1|1].left>=w)
50 updata(i<<1|1,w);
51 tree[i].left=max(tree[i<<1].left,tree[i<<1|1].left);
52 }
53 }
54
55 int main()
56 {
57 int i;
58 __int64 w;
59 // freopen("in.txt","r",stdin);
60 while(scanf("%I64d%I64d%d",&H,&W,&n)==3)
61 {
62 build(1,1,n);
63 for(i=0;i<n;i++)
64 {
65 ans=-1;
66 scanf("%I64d",&w);
67 updata(1,w);
68 printf("%d\n",ans);
69 }
70 }
71 return 0;
72 }
原文地址:https://www.cnblogs.com/ka200812/p/2244879.html