[CTSC2018]混合果汁 二分 套 主席树上二分
Posted 昵称很长很长真是太好了
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CTSC2018]混合果汁 二分 套 主席树上二分相关的知识,希望对你有一定的参考价值。
题意:
n种果汁,第iii种果汁的美味程度是
d
i
d_i
di有
l
i
l_i
li升,价格是
p
i
p_i
pi升
m
m
m个询问,要求使用果汁的总量不小于
L
i
m
Lim
Lim,价格不超过
G
G
G,最大化所用的果汁的美味程度最小值
思路:
大体思路:
首先二分出来一个taste,然后在比taste高的里面去找一些价格少的,且能凑到L升的果汁,检查是否能凑出。
我们发现题目询问很多次,那么我们对于每一次的询问二分,在二分检查时肯定不可以O(n)去检查,因为这样时间复杂度就变成了
O
(
m
∗
n
∗
l
o
g
n
)
O(m*n*logn)
O(m∗n∗logn)了,我么利用主席树。
首先把按照
t
a
s
t
e
taste
taste排序,二分一个答案
t
a
s
t
e
taste
taste,那么我们肯定是贪心地选择美味程度不小于
t
a
s
t
e
taste
taste的并且最便宜的果汁
可以发现其具有单调性,考虑二分一个
t
a
s
t
e
taste
taste给美味程度不小于
t
a
s
t
e
taste
taste的果汁建立一颗以价格为下标的线段树
每个节点记录一下果汁总量和价格和,这样就可以在线段树上二分得到
L
L
L对应的价格了
代码:
#include<bits/stdc++.h>
//#define int long long
#define endl '\\n'
using namespace std;
const int maxn=1e5+10;
struct E{
int taste,price,v;
bool operator <(const E & a)const{
return taste<a.taste;
}
}a[maxn];
int n,m,cnt;
int rt[maxn];
long long treecost[maxn*50],treesum[maxn*50];
int ls[maxn*50],rs[maxn*50];
void updata(int &node,int start,int ends,int lst,long long pos,long long val){ //val 多少升
node=++cnt;
ls[node]=ls[lst];
rs[node]=rs[lst];
treecost[node]=treecost[lst]+pos*val;
treesum[node]=treesum[lst]+val;
if(start==ends) return ;
int mid=(start+ends)>>1;
if(pos<=mid) updata(ls[node],start,mid,ls[lst],pos,val);
else updata(rs[node],mid+1,ends,rs[lst],pos,val);
}
long long sumnow;
//sum 表示的是容积
bool query(int start,int ends,int x,int y,long long rem){
if(treesum[y]-treesum[x]<rem) return false;
if(start==ends){
sumnow+=rem*start;
return true;
}
int mid=(start+ends)>>1;
long long lsum=treesum[ls[y]]-treesum[ls[x]];
if(lsum>=rem){
return query(start,mid,ls[x],ls[y],rem);
}
else{
sumnow+=treecost[ls[y]]-treecost[ls[x]];
return query(mid+1,ends,rs[x],rs[y],rem-lsum);
}
}
int imax=1;
bool che(int x,long long cost,long long tot){
sumnow=0;
if(query(1,imax,rt[x-1],rt[n],tot)==false) return false;
return sumnow<=cost;
}
signed main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i].taste>>a[i].price>>a[i].v;
imax=max(imax,a[i].price);
}
sort(a+1,a+1+n);
for(int i=1;i<=n;i++){
updata(rt[i],1,imax,rt[i-1],a[i].price,a[i].v);
}
for(int i=1;i<=m;i++){
long long pric,L;
cin>>pric>>L;
int l=1,r=n,ans=-1;
while(l<=r){
int mid=(l+r)>>1;
if(che(mid,pric,L)){
ans=a[mid].taste;
l=mid+1;
}
else r=mid-1;
}
cout<<ans<<endl;
}
}
以上是关于[CTSC2018]混合果汁 二分 套 主席树上二分的主要内容,如果未能解决你的问题,请参考以下文章