Live2D

Solution -「CTSC 2018」「洛谷 P4602」混合果汁

\(\mathcal{Description}\)

  Link.

  \(n\) 种果汁,第 \(i\) 种美味度为 \(d_i\),每升价格 \(p_i\),一共 \(l_i\) 升。\(m\) 组询问,给定花费上限 \(g\) 和果汁需求量 \(L\),求混合多种果汁以满足要求时,所用果汁最小美味度的最大值。

  \(n,m,p_i\le10^5\)

\(\mathcal{Solution}\)

  最小值最大,显然二分。

  需要 check:能否用美味度不小于 \(mid\) 的果汁混合出 \(L\) 升,使得价格不超过 \(g\)

  没有美味度的限制,贪心地用单价更低的果汁就好啦!

  回归到原问题,以按美味度降序排列后的果汁编号为版本轴建主席树,树是以单价为下标的权值线段树。外层二分出 \(mid\),再在以 \(mid\) 为根的树上走,贪心地购买果汁(先买左子树,不够再去右子树)。

  就完了 qwq。复杂度 \(\mathcal O(n\log^2n)\)

\(\mathcal{Code}\)

#include <cstdio>
#include <algorithm>

const int MAXN = 1e5;
int n, m, root[MAXN + 5];

typedef long long LL;

inline LL rint () {
	LL x = 0; char s = getchar ();
	for ( ; s < '0' || '9' < s; s = getchar () );
	for ( ; '0' <= s && s <= '9'; s = getchar () ) x = x * 10 + ( s ^ '0' );
	return x;
}

struct Juice {
	int d, p, l;
	inline void read () { d = rint (), p = rint (), l = rint (); }
	inline bool operator < ( const Juice t ) const { return d > t.d; }
} juice[MAXN + 5];

struct PersistentSegmentTree {
	static const int MAXND = MAXN * 40;
	int cntnd, ch[MAXND + 5][2];
	LL sum[MAXND + 5], prc[MAXND + 5];

	inline void build ( int& rt, const int l, const int r ) {
		rt = ++ cntnd;
		if ( l == r ) return ;
		int mid = l + r >> 1;
		build ( ch[rt][0], l, mid ), build ( ch[rt][1], mid + 1, r );
	}

	inline void pushup ( const int rt ) {
		sum[rt] = sum[ch[rt][0]] + sum[ch[rt][1]];
		prc[rt] = prc[ch[rt][0]] + prc[ch[rt][1]];
	}

	inline void insert ( int& rt, const int l, const int r, const int p, const int v ) {
		int old = rt, mid = l + r >> 1; rt = ++ cntnd;
		ch[rt][0] = ch[old][0], ch[rt][1] = ch[old][1], sum[rt] = sum[old], prc[rt] = prc[old];
		if ( l == r ) return sum[rt] += v, prc[rt] += 1ll * v * p, void ();
		if ( p <= mid ) insert ( ch[rt][0], l, mid, p, v );
		else insert ( ch[rt][1], mid + 1, r, p, v );
		pushup ( rt );
	}

	inline LL buy ( const int rt, const int l, const int r, LL money, LL need ) {
		if ( sum[rt] < need || money < 0 ) return -1;
		if ( l == r ) return need * l <= money ? need * l : -1;
		int mid = l + r >> 1;
		if ( sum[ch[rt][0]] >= need ) return buy ( ch[rt][0], l, mid, money, need );
		else {
			LL t = buy ( ch[rt][1], mid + 1, r, money - prc[ch[rt][0]], need - sum[ch[rt][0]] );
			return ~ t ? t + prc[ch[rt][0]] : -1;
		}
	}
} pst;

int main () {
	n = rint (), m = rint ();
	int mxp = 0;
	for ( int i = 1; i <= n; ++ i ) {
		juice[i].read ();
		if ( mxp < juice[i].p ) mxp = juice[i].p;
	}
	std::sort ( juice + 1, juice + n + 1 );
	pst.build ( root[0], 1, mxp );
	for ( int i = 1; i <= n; ++ i ) {
		pst.insert ( root[i] = root[i - 1], 1, mxp, juice[i].p, juice[i].l );
	}
	for ( LL g, L; m --; ) {
		g = rint (), L = rint ();
		int l = 1, r = n;
		LL ans = -1, tmp;
		while ( l <= r ) {
			int mid = l + r >> 1;
			if ( ~ pst.buy ( root[mid], 1, mxp, g, L ) ) r = ( ans = mid ) - 1;
			else l = mid + 1;
		}
		printf ( "%d\n", ~ ans ? juice[ans].d : -1 );
	}
	return 0;
}
posted @ 2020-08-07 20:48  Rainybunny  阅读(109)  评论(0编辑  收藏  举报