[CTSC2018]混合果汁
[CTSC2018]混合果汁
题目大意:
有\(n(n\le10^5)\)种果汁,每种果汁有三个属性:美味度\(d_i\)、单价\(p_i\)和最大体积\(v_i(d_i,p_i,v_i\le10^5)\)。有\(m(m\le10^5)\)个人来买混合果汁,并且希望在价格不超过\(g_i\)的情况下买到体积至少为\(l_i(g_i,l_i\le10^9)\)的混合果汁。定义一种混合果汁的美味度为构成此种混合果汁的所有果汁中最小的美味度。求每个人能喝到的美味度最大是多少?
思路:
对所有果汁的\(d_i\)排序。建立主席树维护单价区间能购买到的最大体积之和与总金额之和。对于每个人二分答案\(k\),在主席树上查找美味度不小于\(k\),尽可能选择单价小的果汁最多能购买的混合果汁体积。若体积大于\(l_i\)则说明答案\(\ge k\)。时间复杂度\(\mathcal O(n\log^2 n)\)。
源代码:
#include<cstdio>
#include<cctype>
#include<algorithm>
typedef long long int64;
inline int64 getint() {
register char ch;
while(!isdigit(ch=getchar()));
register int64 x=ch^'0';
while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
return x;
}
const int N=1e5+1,logN=18;
int n,m,lim,tmp[N];
struct Juice {
int d,p,v;
bool operator < (const Juice &rhs) const {
return d<rhs.d;
}
};
Juice juice[N];
class FotileTree {
private:
struct Node {
int64 v,s;
int left,right;
};
Node node[N*logN];
int sz,new_node(const int &q) {
node[++sz]=node[q];
return sz;
}
public:
int root[N];
void insert(const int &q,int &p,const int &b,const int &e,const int &g,const int &v) {
p=new_node(q);
node[p].v+=v;
node[p].s+=(int64)g*v;
if(b==e) return;
const int mid=(b+e)>>1;
if(g<=mid) insert(node[q].left,node[p].left,b,mid,g,v);
if(g>mid) insert(node[q].right,node[p].right,mid+1,e,g,v);
}
int64 query(const int &q,const int &p,const int &b,const int &e,const int64 &g) {
if(b==e) return std::min(g/b,node[p].v-node[q].v);
const int mid=(b+e)>>1;
const int64 tmp1=node[node[p].left].s-node[node[q].left].s;
const int64 tmp2=node[node[p].left].v-node[node[q].left].v;
if(tmp1==g) return tmp2;
if(tmp1>g) {
return query(node[q].left,node[p].left,b,mid,g);
} else {
return tmp2+query(node[q].right,node[p].right,mid+1,e,g-tmp1);
}
}
};
FotileTree t;
inline bool check(const int &k,const int64 &g,const int64 &v) {
return t.query(t.root[tmp[k]-1],t.root[n],1,lim,g)>=v;
}
int main() {
n=getint(),m=getint();
for(register int i=1;i<=n;i++) {
const int d=getint(),p=getint(),v=getint();
juice[i]=(Juice){d,p,v};
lim=std::max(lim,p);
}
std::sort(&juice[1],&juice[n+1]);
for(register int i=1;i<=n;i++) {
const int &d=juice[i].d,&p=juice[i].p,&v=juice[i].v;
if(d!=juice[tmp[tmp[0]]].d) tmp[++tmp[0]]=i;
t.insert(t.root[i-1],t.root[i],1,lim,p,v);
}
for(register int i=0;i<m;i++) {
const int64 g=getint(),v=getint();
int l=1,r=tmp[0];
while(l<=r) {
const int mid=(l+r)>>1;
if(check(mid,g,v)) {
l=mid+1;
} else {
r=mid-1;
}
}
printf("%d\n",check(l-1,g,v)?juice[tmp[l-1]].d:-1);
}
return 0;
}