题目大意
n个房间各有一些需要更换的台灯。每个月买m盏,包括上月累积,从左到右对各房间换灯泡,如果房间里需要更换的数量大于手中的灯泡数则跳过。询问某月累计对多少房间更换灯泡,以及剩下的灯泡数。
思路
线段树维护区间最小值,每次查询左边第一个小于手中灯泡数的房间。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define INF 0x3f3f3f3f
#define rep0(i, n) for (int i = 0; i < n; i++)
#define rep1(i, n) for (int i = 1; i <= n; i++)
#define rep_0(i, n) for (int i = n - 1; i >= 0; i--)
#define rep_1(i, n) for (int i = n; i > 0; i--)
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
#define MIN(x, y) (((x) < (y)) ? (x) : (y))
#define mem(x, y) memset(x, y, sizeof(x))
#define MAXN 100010
using namespace std;
struct Node
{
int mn;
} tree[MAXN << 2];
int ans[MAXN], rm[MAXN], qu[MAXN];
int a[MAXN];
void push_up(int rt, int l, int r)
{
if (l == r)
return;
tree[rt].mn = MIN(tree[rt << 1].mn, tree[rt << 1 | 1].mn);
}
void build(int rt, int l, int r)
{
if (l == r)
{
tree[rt].mn = a[l];
return;
}
int mid = (l + r) >> 1;
build(rt << 1, l, mid);
build(rt << 1 | 1, mid + 1, r);
push_up(rt, l, r);
}
int update(int rt, int l, int r, int val)
{
if (tree[rt].mn > val)
return 0;
if (l == r)
{
int tmp = tree[rt].mn;
tree[rt].mn = INF;
return tmp;
}
int mid = (l + r) >> 1;
int ans = 0;
if (tree[rt << 1].mn <= val)
ans = update(rt << 1, l, mid, val);
else if (tree[rt << 1 | 1].mn <= val)
ans = update(rt << 1 | 1, mid + 1, r, val);
push_up(rt, l, r);
return ans;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
#endif // ONLINE_JUDGE
int n, m, q, mx_mon = 0;
scanf("%d %d", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%d", a + i);
build(1, 1, n);
scanf("%d", &q);
for (int i = 1; i <= q; i++)
{
scanf("%d", qu + i);
mx_mon = MAX(mx_mon, qu[i]);
}
int cnt = n, lmp = 0, mon = 1;
for (; mon <= mx_mon; mon++)
{
if (!cnt)
{
ans[mon] = n - cnt;
rm[mon] = lmp;
continue;
}
int tmp;
lmp += m;
while (cnt && (tmp = update(1, 1, n, lmp)))
{
cnt--;
lmp -= tmp;
}
ans[mon] = n - cnt;
rm[mon] = lmp;
}
for (int i = 1; i <= q; i++)
printf("%d %d\n", ans[qu[i]], rm[qu[i]]);
return 0;
}