题解
题目大意 给你n个房间 每个房间需要k[i]个灯泡 每天你只能获得m个灯泡 q次询问 问第几天安装了几个房间的灯泡 剩余多少未使用灯泡
安装灯泡的条件是 从左向右查看房间 如果房间手中灯泡满足需求安装数量则安装 然后在上次安装的位置继续向右 每天都是从最左端开始检查
使用线段树存储每个需求量的下标位置 维护满足小于等于k的最小下标
AC代码
#include <stdio.h>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 1e5 + 10;
const int MAXD = 1e4 + 1010;
int a[MAXN];
queue<int> d[MAXD]; //queue头皮发麻的空间复杂度
int x[MAXN], y[MAXN];
struct node
{
int l, r, v;
}tree[MAXD << 2];
inline void PushUp(int x)
{
tree[x].v = min(tree[x << 1].v , tree[x << 1 | 1].v);
}
void Build(int x, int l, int r)
{
tree[x].l = l, tree[x].r = r, tree[x].v = 0;
if (l == r)
{
if (d[l].empty()) //在这个值上没有房间则为INF
tree[x].v = INF;
else
tree[x].v = d[l].front(), d[l].pop();
}
else
{
int m = l + r >> 1;
Build(x << 1, l, m);
Build(x << 1 | 1, m + 1, r);
PushUp(x);
}
}
void Update(int x, int l, int r)
{
int xl = tree[x].l, xr = tree[x].r;
if (l <= xl && r >= xr)
{
if (d[l].empty())
tree[x].v = INF;
else
tree[x].v = d[l].front(), d[l].pop();
}
else
{
int xm = xl + xr >> 1;
if (xm >= l)
Update(x << 1, l, r);
else
Update(x << 1 | 1, l, r);
PushUp(x);
}
}
int Query(int x, int l, int r)
{
int xl = tree[x].l, xr = tree[x].r;
if (l <= xl && r >= xr)
return tree[x].v;
else
{
int xm = xl + xr >> 1;
int res = INF;
if (xm >= l)
res = min(res, Query(x << 1, l, r));
if (xm < r)
res = min(res, Query(x << 1 | 1, l, r));
return res;
}
}
int main()
{
#ifdef LOCAL
freopen("C:/input.txt", "r", stdin);
#endif
int n, m, q;
cin >> n >> m;
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
d[a[i]].push(i);
}
Build(1, 1, 1e4 + 1000);
int j = 0, k = 0;
for (int i = 1; i < MAXN; i++)
{
if (j < n)
k += m;
int res = Query(1, 1, k);
while (res != INF)
{
j++;
k -= a[res];
Update(1, a[res], a[res]); //刷新
res = Query(1, 1, k);
}
x[i] = j, y[i] = k;
}
cin >> q;
for (int i = 0; i < q; i++)
{
int p;
scanf("%d", &p);
printf("%d %d\n", x[p], y[p]);
}
return 0;
}