【BZOJ】5343: [Ctsc2018]混合果汁 主席树&二分

传送门:bzoj5343


题解

可以二分一个答案 d d d,每次贪心从美味度 ≥ d \geq d d p p p最小的选起(尽可能地选更大体积的饮料),所以最优选择方案也是固定的。按 d d d建主席树。二分查询即可。


代码

#include
#define RI register
#define gc getchar()
#define si isdigit(ch) 
#define lc(k) t[(k)].ch[0]
#define rc(k) t[(k)].ch[1]
#define mid (((l)+(r))>>1)
using namespace std;
const int N=1e5+10;
typedef long long ll;

int n,m,cs,P[2],D[N];
ll G,V;
int cnt,rt[N];

struct juice{
	int d,p,l;
	bool operator <(const juice&ky)const{
	   return d<ky.d;
	}
}drk[N];

struct node{
   int ch[2];ll sv,sc;
   node(){};
   node(int sonl,int sonr,ll sv_,ll sc_){ch[0]=sonl;ch[1]=sonr;sv=sv_;sc=sc_;}
}t[N*33];

char ch;

template<class T>
inline void rd(T &x)
{
	ch=gc;x=0;
	for(;!si;ch=gc);
	for(;si;ch=gc) x=x*10+(ch^48);
}

inline void ins(int pre,int &k,int l,int r,int pos,int vv)
{
	if(k==pre) t[(k=++cnt)]=node(lc(pre),rc(pre),t[pre].sv,t[pre].sc);
	t[k].sv+=vv;t[k].sc+=1ll*pos*vv;
	if(l==r) return;
	if(pos<=mid) ins(lc(pre),lc(k),l,mid,pos,vv);
	else ins(rc(pre),rc(k),mid+1,r,pos,vv);
}

inline ll query(int pre,int k,int l,int r,ll res)
{
	if(!k) return 0;
	if(l==r) return min(res/l,t[k].sv-t[pre].sv);
	ll sum=t[lc(k)].sc-t[lc(pre)].sc;
	if(res<=sum) return query(lc(pre),lc(k),l,mid,res);
	return t[lc(k)].sv-t[lc(pre)].sv+query(rc(pre),rc(k),mid+1,r,res-sum);
}

int main(){
	RI int i,j,l,r,ans;
	rd(n);rd(m);P[0]=N;
	for(i=1;i<=n;++i){
	  rd(drk[i].d),rd(drk[i].p),rd(drk[i].l);
	  P[0]=min(P[0],drk[i].p);P[1]=max(P[1],drk[i].p);
	}
	sort(drk+1,drk+n+1);
    D[(cs=1)]=drk[1].d;
	for(i=1;i<=n;++i){
		if(D[cs]!=drk[i].d){D[++cs]=drk[i].d;rt[cs]=rt[cs-1];}
		ins(rt[cs-1],rt[cs],P[0],P[1],drk[i].p,drk[i].l); 
	}
	for(;m;--m){
		rd(G);rd(V);
		l=1;r=cs;ans=-1;
		for(;l<=r;){
			if(query(rt[mid-1],rt[cs],P[0],P[1],G)>=V){
				ans=D[mid];l=mid+1;
			}else r=mid-1;
		}
		printf("%d\n",ans);
	}
	return 0;
}

你可能感兴趣的:(二分,主席树)