原题链接:https://www.luogu.com.cn/problem/P4602
题意解读:在一堆果汁中选出若干果汁,使得最小的美味度最大,且总体价格小于等于g,总体体积大于L,求这个最大的美味度。
解题思路:
显然,应该对答案进行二分,二分到一个美味度x,那么接下来check()函数要做的事,就是在所有美味度>=x的果汁中,
查询出取到体积L时所需要付出的总价格sum,只要sum<=g并且所有美味度>=x的果汁的总可用体积<=L,则check结果为true,继续找更大的美味度。
查询的时候,可以使用贪心策略,为了不超总价,显然价格越低的越应该优先选择。
如何在美味度>=x的果汁查询正好取到体积L的果汁总价格,并且还优先差价格小的呢?可以借助权值线段树!
用果汁价格作为权值,果汁能取的体积作为权值的数量cnt,然后维护区间所有果汁的总价格sum,就可以计算权值数量前L小的果汁总价格,
这里可以参考:https://www.cnblogs.com/jcwy/p/18674205
由于要实现在所有比美味度x大的果汁中查询,可以用可持久化线段树,将果汁按美味度从大到小排序,root[i]线段树就是维护所有美味度大于i位置美味度的果汁情况,对位置进行二分即可。
100分代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
typedef long long LL;
struct Juice
{
int d, p, l;
bool operator < (const Juice &j) const &
{
return d > j.d;
}
} a[N];
struct Node
{
int L, R;
LL cnt; //区间所有可用体积之和
LL sum; //区间所有可用果汁价格之和
} tr[N * 80];
int root[N], idx;
LL g, L;
int n, m;
//基于根为pre的线段树复制,并将值为v的cnt加上num,并更新相应的sum
int update(int pre, int l, int r, int v, int num)
{
int u = ++idx;
tr[u] = tr[pre];
tr[u].cnt += num;
tr[u].sum += 1ll * v * num;
if(l == r) return u;
int mid = l + r >> 1;
if(v <= mid) tr[u].L = update(tr[pre].L, l, mid, v, num);
else tr[u].R = update(tr[pre].R, mid + 1, r, v, num);
return u;
}
//在根为u的线段树中查询权值前k小的所有价格之和
LL query(int u, int l, int r, int k)
{
if(l == r) return 1ll * l * k;
int mid = l + r >> 1;
LL leftcnt = tr[tr[u].L].cnt;
if(leftcnt >= k) return query(tr[u].L, l, mid, k);
else return tr[tr[u].L].sum + query(tr[u].R, mid + 1, r, k - leftcnt);
}
bool check(int x)
{
LL res = query(root[x], 1, N, L);
if(res <= g && tr[root[x]].cnt >= L) return true; //总价格<=g且可用的总体积>=L
return false;
}
int main()
{
cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> a[i].d >> a[i].p >> a[i].l;
sort(a + 1, a + n + 1);
for(int i = 1; i <= n; i++) root[i] = update(root[i - 1], 1, N, a[i].p, a[i].l);
while(m--)
{
cin >> g >> L;
int l = 1, r = n, ans = -1;
while(l <= r)
{
int mid = l + r >> 1;
if(check(mid)) ans = a[mid].d, r = mid - 1; //mid更小也就是美味度更大
else l = mid + 1;
}
cout << ans << endl;
}
return 0;
}
标签:进阶,int,洛谷题,sum,tr,P4602,mid,果汁,美味 From: https://www.cnblogs.com/jcwy/p/18683708