计蒜客 30996 - Lpl and Energy-saving Lamps - [线段树][2018ICPC南京网络预赛G题]
题目链接:https://nanti.jisuanke.com/t/30996
During tea-drinking, princess, amongst other things, asked why has such a good-natured and cute Dragon imprisoned Lpl in the Castle? Dragon smiled enigmatically and answered that it is a big secret. After a pause, Dragon added:
— We have a contract. A rental agreement. He always works all day long. He likes silence. Besides that, there are many more advantages of living here in the Castle. Say, it is easy to justify a missed call: a phone ring can't reach the other side of the Castle from where the phone has been left. So, the imprisonment is just a tale. Actually, he thinks about everything. He is smart. For instance, he started replacing incandescent lamps with energy-saving lamps in the whole Castle...
Lpl chose a model of energy-saving lamps and started the replacement as described below. He numbered all rooms in the Castle and counted how many lamps in each room he needs to replace.
At the beginning of each month, Lpl buys mm energy-saving lamps and replaces lamps in rooms according to his list. He starts from the first room in his list. If the lamps in this room are not replaced yet and Lpl has enough energy-saving lamps to replace all lamps, then he replaces all ones and takes the room out from the list. Otherwise, he'll just skip it and check the next room in his list. This process repeats until he has no energy-saving lamps or he has checked all rooms in his list. If he still has some energy-saving lamps after he has checked all rooms in his list, he'll save the rest of energy-saving lamps for the next month.
As soon as all the work is done, he ceases buying new lamps. They are very high quality and have a very long-life cycle.
Your task is for a given number of month and descriptions of rooms to compute in how many rooms the old lamps will be replaced with energy-saving ones and how many energy-saving lamps will remain by the end of each month.
样例输入:
5 4 3 10 5 2 7 10 5 1 4 8 7 2 3 6 4 7
样例输出:
4 0 1 1 3 6 5 1 5 1 2 0 3 2 4 4 3 6 5 1
题意:
有一修理工,知道了一个城堡里的 n 个房间里的灯泡需要更换,每个房间需要更换的灯泡数是 k[1~n],
现在修理工每个月固定买进 m 个节能灯,进行更换操作:
修理工把这 1~n 个房间按顺序从左到右写在一张列表上,每次都从最左边开始选择房间,
假设选到的房间内需要更换的灯泡数量超过手头的节能灯数量,就跳过,直到找到第一个小于手头节能灯数目的,
他会把节能灯换上去,然后继续往右遍历房间。而且,修理工一个月只遍历一次房间,同时,若所有房间灯泡全部换完,则不再购入节能灯,停止工作。
且若当月遍历完房间之后,还有剩下若干节能灯,则留到下个月,和下个月购入的 m 个节能灯合并到一起。
现在给出 q 个查询,每个查询包含一个数字 d,表示查询第 d 个月的工作完毕时,有多少间房间灯泡已经更换完毕,修理工手头还有多少个节能灯。
题解:
模拟,枚举月份,对于第 i 个月:
假设已知本月购买进 m 个节能灯后,手头节能灯数为 K,
找到从左往右遍历的第一个待更换灯泡数比 K 小的房间,更换灯泡即可。
那么,如何找到从左到右第一个待更换灯泡数比 K 小的房间呢……用线段树。
用一个能满足 ①单点修改 ②查询第一个比 k 小的数的位置 的线段树就可以了。
AC代码:
#include<bits/stdc++.h> using namespace std; const int maxn=1e5+10; const int INF=0X3f3f3f3f; int n,m,q; int k[maxn],d[maxn]; struct Ans{ int room; //已经把灯泡更换完的房间 int lamp; //手头剩下的节能灯数量 }ans[maxn]; /********************************* Segment Tree - st *********************************/ struct Node{ int l,r; int val; }node[4*maxn]; void pushup(int root) { node[root].val=min(node[root*2].val,node[root*2+1].val); } void build(int root,int l,int r) { if(l>r) return; node[root].l=l; node[root].r=r; node[root].val=0; if(l==r) node[root].val=k[l]; else { int mid=l+(r-l)/2; build(root*2,l,mid); build(root*2+1,mid+1,r); pushup(root); } } void update(int root,int pos,int val) { if(node[root].l==node[root].r) { node[root].val=val; return; } int mid=node[root].l+(node[root].r-node[root].l)/2; if(pos<=mid) update(root*2,pos,val); if(pos>mid) update(root*2+1,pos,val); pushup(root); } int query(int root,int k) //查询第一个比k小的数位置 { if(node[root].val>k) return 0; if(node[root].l==node[root].r) return node[root].l; else { if(node[root*2].val<=k) return query(root*2,k); else if(node[root*2+1].val<=k) return query(root*2+1,k); } } /********************************* Segment Tree - ed *********************************/ int main() { cin>>n>>m; for(int i=1;i<=n;i++) cin>>k[i]; build(1,1,n); int lamp=0,tot=0; for(int mon=1;mon<maxn;mon++) { if(tot>=n) { ans[mon].room=tot; ans[mon].lamp=lamp; continue; } lamp+=m; while(1) { int pos=query(1,lamp); if(pos==0) break; lamp-=k[pos]; update(1,pos,INF); tot+=1; } ans[mon].room=tot; ans[mon].lamp=lamp; } cin>>q; for(int i=1,d;i<=q;i++) { cin>>d; printf("%d %d\n",ans[d].room,ans[d].lamp); } }