CF1439C Greedy Shopping

比较好的线段树二分.   

先考虑没有修改如何做:   

对于一个 $\mathrm{y}$, 先找到第一个可以选的 $\mathrm{a[i]}$, 然后尽量选这个连续段.   

显然,每当一个连续段停止时 $\mathrm{y}$ 的规模至少缩小了 $\mathrm{\frac{1}{2}}$.    

所以,连续段的个数不会超过 $\mathrm{log n}$.  

然后静态做的话这个东西直接在线段树上搜索一下就行.   

如果加上修改,就直接打 $\mathrm{lazy}$ 标记.   

直接查询的话会比较麻烦,可以将 $\mathrm{y}$ 增大前 $\mathrm{x-1}$ 的和强制从 $1$ 开始选.   

#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
#define N  200009 
#define pb push_back 
#define ll long long 
#define ls now << 1
#define rs now << 1 | 1
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std; 
ll sum[N<<2]; 
int n,Q,a[N],len[N<<2],lazy[N<<2],mi[N<<2];       
void mark(int now, int v) {
	lazy[now]=mi[now]=v; 
	sum[now] = 1ll * len[now] * v;  
}
void pushdown(int now) {
	if(lazy[now]) {
		mark(ls, lazy[now]); 
		mark(rs, lazy[now]); 
		lazy[now] = 0; 
	}
}
void pushup(int now) {
	mi[now] = min(mi[ls], mi[rs]); 
	sum[now] = sum[ls] + sum[rs]; 
}
void build(int l, int r, int now) {
	len[now] = r - l + 1;  
	if(l == r) {
		mi[now] = sum[now] = a[l];     
		return ; 
	}
	int mid=(l+r)>>1;  
	build(l, mid, ls); 
	build(mid + 1, r, rs);
	pushup(now);
}  
void update(int l,int r,int now,int L,int R,int v) {
	if(l>=L&&r<=R) {
		mark(now, v); 
		return ; 
	}
	pushdown(now);  
	int mid=(l+r)>>1;  
	if(L<=mid)  update(l, mid, ls, L, R, v); 
	if(R>mid)   update(mid + 1, r, rs, L, R, v); 
	pushup(now); 
}
int query(int l, int r, int now, ll &v) {
	if(v < mi[now]) return 0; 
	if(l == r) {
		int d = 0; 
		if(sum[now] <= v) v -= sum[now], d = 1;  
		return d; 
	}
	pushdown(now); 
	int mid=(l+r)>>1;   
	if(mi[ls] > v) return query(mid + 1, r, rs, v);  
	else {
		if(sum[ls] <= v) {
			v -= sum[ls]; 
			return len[ls] + query(mid + 1, r, rs, v); 
		} 
		else {
			int dl = query(l, mid, ls, v);
			int dr = query(mid+1,r,rs, v);  
			return dl + dr; 
		}
	}    
}
// 第一个小于 v 的位置.  
int search(int l,int r,int now,int v) {
	if(l == r) {
		return l; 
	}
	pushdown(now); 
	int mid = (l + r) >> 1;     
	if(mi[ls] < v) return search(l, mid, ls, v); 
	else return search(mid + 1, r, rs, v); 
}
ll get(int l,int r,int now,int L,int R) {
	if(l >= L && r <= R) {
		return sum[now]; 
	}
	pushdown(now); 
	int mid=(l+r)>>1;  
	if(L<=mid&&R>mid) {
		return get(l,mid,ls,L,R)+get(mid+1,r,rs,L,R); 
	}
	else if(L<=mid) return get(l,mid,ls,L,R); 
	else return get(mid+1,r,rs,L,R);  	
}
int main() {
	// setIO("input"); 
	scanf("%d%d",&n,&Q);  
	for(int i=1;i<=n;++i) {
		scanf("%d",&a[i]); 
	}   
	build(1, n, 1); 
	for(int i=1;i<=Q;++i) {
		int op,x,y;  
		scanf("%d%d%d",&op,&x,&y);  
		if(op == 1) {
			// [1, x] 与 y 取 max.  
			if(mi[1] < y) {
				int pos = search(1, n, 1, y);  
				if(pos <= x) {
					update(1, n, 1, pos, x, y);  
				}
			}
		}
		else {
			ll o = 0;  
			if(x > 1) {
				o = get(1, n, 1, 1, x - 1); 
			}
			o += y; 
			printf("%d\n", query(1, n, 1, o) - (x - 1));    
		}
	}
	return 0; 
}

  

posted @ 2021-10-21 22:09  guangheli  阅读(25)  评论(0)    收藏  举报