G. Lpl and Energy-saving Lamps;
题意:每个月买m个灯,依次从1~n的房间去装灯,每个房间都有需要的灯数
ki
k
i
,当你有灯数大于等于
ki
k
i
时才能装。问你第q个月,装了几个房间,剩了多少盏灯?
分析:
按照
ki
k
i
排序后,线段树维护区间最小编号(两个tag,房间编号和
ki
k
i
)。
注意:预处理时,房间都装完后,就不在买灯,答案固定了。
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
using namespace std;
#define met(s) memset(s, 0, sizeof(s))
#define rep(i, a, b) for(int i = a; i <= b; ++i)
template <class T> inline void scan_d(T &ret) {
char c; ret = 0;
while ((c = getchar()) < '0' || c > '9');
while (c >= '0' && c <= '9') {
ret = ret * 10 + (c - '0'), c = getchar();}}
typedef long long LL;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int INF = 0x3f3f3f3f;
const int mod = 1e9 + 7;
const int MAXN = 4e5 + 10;
pii dp[MAXN], a[MAXN], pp[MAXN];
int has[MAXN];
inline void up(int rt) {
if(dp[rt << 1].second > dp[rt << 1 | 1].second) dp[rt] = dp[rt << 1 | 1];
else dp[rt] = dp[rt << 1];
}
inline void build(int rt, int L, int R) {
if(L == R) {
dp[rt].first = a[L].first;
dp[rt].second = a[L].second;
return ;
}
int mid = (L + R) >> 1;
build(rt << 1, L, mid);
build(rt << 1 | 1, mid + 1, R);
up(rt);
}
inline void ut(int rt, int L, int R, int x) {
if(L == R) {
dp[rt].first = 0, dp[rt].second = INF;
return ;
}
int mid = (L + R) >> 1;
if(x <= mid) ut(rt << 1, L, mid, x);
if(x > mid) ut(rt << 1 | 1, mid + 1, R, x);
up(rt);
}
inline pii qr(int rt, int L, int R, int l, int r) {
if(l <= L && R <= r) return dp[rt];
int mid = (L + R) >> 1;
pii ans; ans.second = INF;
if(l <= mid) {
pii cnt = qr(rt << 1, L, mid, l, r);
if(cnt.second < ans.second) ans = cnt;
}
if(r > mid) {
pii cnt = qr(rt << 1 | 1, mid + 1, R, l, r);
if(cnt.second < ans.second) ans = cnt;
}
return ans;
}
int main() {
int n, m, q;
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; ++i) {
scanf("%d", &a[i].first);
a[i].second = i;
}
sort(a + 1, a + n + 1);
for(int i = 1; i <= n; ++i) has[a[i].second] = i;
build(1, 1, n); int sum = 0, res = 0;
for(int i = 1; i < MAXN; ++i) {
if(res == n) {
pp[i] = pp[i - 1];
continue;
}
sum += m;
while(1) {
int cnt = upper_bound(a + 1, a + n + 1, pii(sum, INF)) - (a + 1);
if(!cnt) break;
pii ans = qr(1, 1, n, 1, cnt);
if(ans.second > n) {
pp[i].first = res, pp[i].second = sum;
break;
}
else {
res++;
pp[i].first = res, pp[i].second = sum - ans.first;
ut(1, 1, n, has[ans.second]);
sum -= ans.first;
if(res == n) break;
// printf("%d %d %d\n", ans.first, ans.second, sum);
}
}
}
scanf("%d", &q);
while(q--) {
int mo;
scanf("%d", &mo);
printf("%d %d\n", pp[mo].first, pp[mo].second);
}
return 0;
}