[CF1526C] Potions

前言

这道题我两年前直接爆切,两年后碰到类似的题:数据结构。

降智严重啊。

题目

CF

题目大意:

\(n\) 瓶药剂,从左往右编号依次是 \(1...n\),每瓶药剂有一个值 \(a_i\) ,表示喝下去之后你可以增加 \(a_i\) 点生命值(\(a_i\) 为负则是减少生命值)。你的初始生命值为 \(0\),从左往右依次选择药剂喝掉(当然也可以不喝),询问最多可以喝多少药剂。过程中要保证生命值不低于0

\(1\le n\le 200000;-10^9\le a_i\le 10^9.\)

讲解

这里有一个优秀的反悔贪心做法。

只要喝不死,就往死里喝。如果喝死了,就把最毒的吐出来!

显然这是正确的,而且只需要一个优先队列即可简单实现。

还有一个蠢一点的做法:先把所有不扣血的药剂全部喝光,得到每个位置的最大生命值。然后贪心选毒性最小的药剂喝掉,用线段树维护是否会毒死。

不过这样实现十分冗长。

代码

std

#include <bits/stdc++.h>
using namespace std;

int main(){
	ios_base::sync_with_stdio(false); cin.tie(0);
	
	int n; cin >> n;
	priority_queue<long long, vector<long long>, greater<long long> > pq;
	long long S = 0;
	
	for(int i = 1;i <= n;i++){
		long long x; cin >> x;
		S += x;
		pq.push(x);
		
		while(S < 0){
			S -= pq.top();
			pq.pop();
		}
	}
	
	cout << (int) pq.size();
}

我就是这个做法...

int h;
struct node
{
	int val,ID;
	bool operator < (const node &px)const{
		if(val != px.val) return val > px.val;
		return ID > px.ID;
	}
}s[MAXN];

#define lc (x<<1)
#define rc (x<<1|1)
struct SegmentTree
{
	LL MIN[MAXN << 2],lz[MAXN << 2];
	
	void up(int x){MIN[x] = Min(MIN[lc],MIN[rc]);}
	
	void down(int x){
		if(!lz[x]) return;
		lz[lc] += lz[x];
		lz[rc] += lz[x];
		MIN[lc] += lz[x];
		MIN[rc] += lz[x];
		lz[x] = 0;
		return;
	}
	
	void Build(int x,int l,int r)
	{
		if(l == r) {MIN[x] = a[l];lz[x] = 0;return;}
		int mid = (l+r) >> 1;
		Build(lc,l,mid); Build(rc,mid+1,r);
		up(x);
	}
	
	void Add(int x,int l,int r,int ql,int qr,LL val)
	{
		if(ql <= l && r <= qr) {MIN[x] += val;lz[x] += val;return ;}
		down(x);
		int mid = (l+r) >> 1;
		if(ql <= mid) Add(lc,l,mid,ql,qr,val);
		if(mid+1 <= qr) Add(rc,mid+1,r,ql,qr,val);
		up(x);
	}
	
	LL Query(int x,int l,int r,int ql,int qr)
	{
		if(ql <= l && r <= qr) return MIN[x];
		down(x);
		LL mid = (l+r) >> 1,ret = INF;
		if(ql <= mid) ret = Min(ret,Query(lc,l,mid,ql,qr));
		if(mid+1 <= qr) ret = Min(ret,Query(rc,mid+1,r,ql,qr));
		return ret;
	}
}st;

int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	n = Read();
	for(int i = 1;i <= n;++ i) 
	{
		a[i] = Read(); 
		if(a[i] >= 0) ans++,S += a[i],a[i] = S;
		else s[++h].val = a[i],s[h].ID = i,a[i] = S;
	}
	st.Build(1,1,n);
	sort(s+1,s+h+1);
	for(int i = 1;i <= h;++ i)
	{
		LL M = st.Query(1,1,n,s[i].ID,n);
		if(M < Abs(s[i].val)) continue;
		ans++;
		st.Add(1,1,n,s[i].ID,n,s[i].val);
	}
	Put(ans);
	return 0;
}
posted @ 2021-05-30 09:16  皮皮刘  阅读(89)  评论(0)    收藏  举报