[CF1439C] Greedy Shopping

[题目链接]

https://codeforces.com/contest/1439/problem/C

[题解]

首先对于 \(1\) 操作 , 对一段前缀取 \(max\) 后 , 整个序列仍然满足单调不增的性质。 在线段树上二分 , 整体赋值即可。

对于 \(2\) 操作 , 注意到取走的数必然是不超过 \(log(N)\) 个连续段。 这是由单调不增的性质得来的。

那么在线段树上再次二分即可。

时间复杂度 : \(O(NlogN)\)

[代码]

#include <bits/stdc++.h>
 
using namespace std;
 
typedef long long LL;
 
const int MN = 5e5 + 5;
 
int N , M , A[MN] , tg[MN << 2] , mn[MN << 2];
LL sum[MN << 2];
 
inline void pushup(int now) {
	sum[now] = sum[now << 1] + sum[now << 1 | 1];
	mn[now] = min(mn[now << 1] , mn[now << 1 | 1]);
}
inline void build(int now , int l , int r) {
	tg[now] = -1;
	if (l == r) {
		sum[now] = mn[now] = A[l];
		return;
	}
	int mid = l + r >> 1;
	build(now << 1 , l , mid) , build(now << 1 | 1 , mid + 1 , r);
	pushup(now); 
}
inline void pushdown(int now , int l , int r) {
	if (tg[now] == -1) return;
	int mid = l + r >> 1;
	mn[now << 1] = mn[now << 1 | 1] = tg[now];
	sum[now << 1] = 1LL * (mid - l + 1) * tg[now]; sum[now << 1 | 1] = 1LL * (r - mid) * tg[now];
	tg[now << 1] = tg[now] , tg[now << 1 | 1] = tg[now]; tg[now] = -1;
	return;
}
inline LL query(int now , int l , int r , int ql , int qr) {
	if (l == ql && r == qr) return sum[now];
	int mid = l + r >> 1; pushdown(now , l , r);
	if (mid >= qr) return query(now << 1 , l , mid , ql , qr);
	else if (mid + 1 <= ql) return query(now << 1 | 1 , mid + 1 , r , ql , qr);
	else return query(now << 1 , l , mid , ql , mid) + query(now << 1 | 1 , mid + 1 , r , mid + 1 , qr);
} 
inline void modify(int now , int l , int r , int ql , int qr , int val) {
	if (l == ql && r == qr) {
		mn[now] = val; sum[now] = 1LL * (r - l + 1) * val;
		tg[now] = val; return;
	}
	int mid = l + r >> 1; pushdown(now , l , r);
	if (mid >= qr) modify(now << 1 , l , mid , ql , qr , val);
	else if (mid + 1 <= ql) modify(now << 1 | 1 , mid + 1 , r , ql , qr , val);
	else modify(now << 1 , l , mid , ql , mid , val) , modify(now << 1 | 1 , mid + 1 , r , mid + 1 , qr , val);
	pushup(now);
}
inline int ask(int now , int l , int r , LL &val) {
	if (val >= sum[now]) {
		val -= sum[now];
		return r - l + 1;
	}
	if (l == r) return 0;
	int mid = l + r >> 1; pushdown(now , l , r);
	int res = 0;
	if (mn[now << 1] <= val) res += ask(now << 1 , l , mid , val);
	if (mn[now << 1 | 1] <= val) res += ask(now << 1 | 1 , mid + 1 , r , val);
	return res;
}
 
int main() {
	
	scanf("%d%d" , &N , &M);
	for (int i = 1; i <= N; ++i) scanf("%d" , &A[i]);
	build(1 , 1 , N);
	for (int i = 1; i <= M; ++i) {
		int op , x; LL y;
		scanf("%d%d%lld" , &op , &x , &y);
		if (op == 1) {
			int l = 1 , r = x , ans = 0;
			while (l <= r) {
				int mid = l + r >> 1;
				if (query(1 , 1 , N , mid , mid) < y) {
					ans = mid;
					r = mid - 1;
				} else l = mid + 1;
			}
			if (ans) modify(1 , 1 , N , ans , x , y);
		} else {
			if (x > 1) y += query(1, 1, N, 1, x - 1);
			printf("%d\n" , ask(1 , 1 , N , y) - (x - 1));
		}
	}	
	return 0;
}
posted @ 2020-11-25 22:51  evenbao  阅读(124)  评论(0编辑  收藏  举报