Lpl and Energy-saving Lamps
题目链接: Lpl and Energy-saving Lamps
题意
你有N个房间(N<1e5),每天买M个灯泡(M<100),每个房间都有需要装的灯泡数,每天装灯泡时,必须从第一个房间到最后一个房间,如果可以装,即手中的灯泡数大于房间需要的灯泡数,就装。总共有Q个询问(Q<1e5),每次询问的天数,小于等于1e4,每次询问输出当前天时,所点亮的房间数和现在手中的灯泡数。
思路
将题目简化,我们即可知道,我们所需要知道的是,当前序列中第一个小于等于手中剩下灯泡的房间数。那么我们用线段树即可,维护最小值,每次优先访问左节点,如果左节点中最小的值小于现在手中的灯泡数时,进行操作,暴力模拟。
代码
#include <bits/stdc++.h>
using namespace std;
#define rep(i,j,k) for(int i = (int)j;i <= (int)k;i ++)
#define per(i,j,k) for(int i = (int)j;i >= (int)k;i --)
#define debug(x) cerr<<#x<<" = "<<(x)<<endl
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
typedef double db;
typedef long long ll;
const int MAXN = (int)1e5+7;
const int INF = (int)0x3f3f3f3f;
#define lson rt<<1
#define rson rt<<1|1
inline int read() { int c = 0, f = 1;char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-') f = -1;ch = getchar();}
while (ch >= '0' && ch <= '9') {c = c * 10 + ch - '0';ch = getchar();}
return c * f;
}
int A[MAXN];
int sum[MAXN<<2];
void PushUp(int rt){sum[rt] = min(sum[lson] , sum[rson]); }
void Build(int l,int r,int rt){
if (l == r){
sum[rt] = A[l];
return ;
}
int m = (l+r)>>1;
Build(l,m,lson);
Build(m+1,r,rson);
PushUp(rt);
}
void Update(int L,int C,int l,int r,int rt){
if (l == r){
sum[rt] = C;
return ;
}
int m = (l+r)>>1;
if (L <= m) Update(L,C,l,m,lson);
else Update(L,C,m+1,r,rson);
PushUp(rt);
}
int Query(int l,int r,int rt,int val){
if (l == r) {
return l;
}
int m = (l+r)>>1;
int ans = INF;
if (sum[lson] <= val) {ans = Query(l,m,lson,val); }
else if (sum[rson] <= val) {ans = Query(m+1,r,rson,val); }
return ans;
}
int room[MAXN];
int rem[MAXN];
int main()
{
int N,M;
N = read(),M = read();
rep(i,1,N) A[i] = read();
Build(1,N,1);
int re = 0;
rep(i,1,100000){
re += M;
if (sum[1] == INF) re -= M;
room[i] = room[i-1];
rem[i] = re;
while (sum[1] <= re) {
int id = Query(1,N,1,re);
re -= A[id];
room[i] ++;
rem[i] -= A[id];
Update(id,INF,1,N,1);
}
}
int Q = read();
while (Q --) {
int d = read();
printf("%d %d\n",room[d],rem[d]);
}
}