1. 程式人生 > >【BZOJ】5343: [Ctsc2018]混合果汁 主席樹&二分

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

題解

可以二分一個答案dd,每次貪心從美味度d\geq dpp最小的選起(儘可能地選更大體積的飲料),所以最優選擇方案也是固定的。可以按dd建主席樹。二分查詢即可。

程式碼

#include<bits/stdc++.h>
#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; }