传送门:https://vjudge.net/contest/349835#problem/A
题意:长度为n的序列代表每个房间的灯泡需求,k为每个月新获得的灯泡,从左往右找当手头的灯泡>=房间的需求时为房间更换灯泡,若没有房间满足则留着下一个月用,q次询问,回答在第i个月装修了多少个房间,手头上的灯泡还剩多少。
思路:线段树维护区间最小值,月份数可达1e5,预处理每一个月份的答案,每个月份用logn的时间从左往右找可以装修的房间,找到则维护答案并单点更新叶子结点为inf代表去除该结点,记录ans数组最后输出就行。
AC代码:
1 #include<iostream> 2 #include<math.h> 3 const int maxn=1e5+50; 4 const int inf=0X3f3f3f3f; 5 using namespace std; 6 7 int n,m,q; 8 int a[4*maxn],A[maxn],que[maxn]; 9 10 struct node{ 11 int num; 12 int res; 13 }ans[maxn]; 14 15 void pushup(int rt){ 16 a[rt]=min(a[rt<<1],a[rt<<1|1]); 17 } 18 19 void build(int l,int r,int rt){ 20 if(l==r){ 21 a[rt]=A[l]; 22 return; 23 } 24 int m=l+r>>1; 25 build(l,m,rt<<1); 26 build(m+1,r,rt<<1|1); 27 pushup(rt); 28 } 29 30 void updata(int p,int x,int l,int r,int rt){ 31 if(l==r){ 32 a[rt]=x; 33 return; 34 } 35 int m=l+r>>1; 36 if(p<=m) 37 updata(p,x,l,m,rt<<1); 38 else 39 updata(p,x,m+1,r,rt<<1|1); 40 pushup(rt); 41 } 42 43 int query(int x,int l,int r,int rt){//从左到右查找第一个大于x的叶子节点位置 44 if(a[rt]>x){//代表没有房间符合 45 return 0; 46 } 47 int m=l+r>>1; 48 if(l==r) return l;//注意返回的不是rt 是 l 49 else{ 50 if(a[rt<<1]<=x) query(x,l,m,rt<<1); 51 else if(a[rt<<1|1]<=x) query(x,m+1,r,rt<<1|1); 52 } 53 } 54 55 int main() 56 { 57 cin>>n>>m; 58 for(int i=1;i<=n;i++) 59 cin>>A[i]; 60 cin>>q; 61 for(int i=1;i<=q;i++){ 62 cin>>que[i]; 63 } 64 build(1,n,1); 65 int nnum=0,nres=0; 66 for(int i=1;i<=1e5+10;i++){ 67 if(nnum>=n){ 68 ans[i].num=nnum; 69 ans[i].res=nres; 70 continue; 71 } 72 nres+=m; 73 while(nres){ 74 int index=query(nres,1,n,1); 75 if(index==0) break;//表示现在没有可以用的房间了 76 nnum++;nres-=A[index]; 77 updata(index,inf,1,n,1); 78 } 79 ans[i].num=nnum; 80 ans[i].res=nres; 81 } 82 for(int i=1;i<=q;i++){ 83 cout<<ans[que[i]].num<<" "<<ans[que[i]].res<<'\n'; 84 } 85 return 0; 86 }