zoukankan      html  css  js  c++  java
  • LOJ 2555 & 洛谷 P4602 [CTSC2018]混合果汁(二分+主席树)

    LOJ 题目链接 & 洛谷题目链接

    题意:商店里有 (n) 杯果汁,第 (i) 杯果汁有美味度 (d_i),单价为 (p_i) 元/升。最多可以添加 (l_i) 升。有 (m) 次询问,每次给出两个数 (G,L),你可以将商店里的一些果汁混合起来,使得他们的总体积不小于 (L) 升,总价格不超过 (G) 元,问:选择的果汁中美味度最小值的最大值是多少。
    (1 leq n,m leq 10^5)(1 leq d_i,p_i,l_i leq 10^5)

    看到这种“最小值最大”的字眼,第一反应应该是二分吧(
    (d) 数组排个序,二分出 (mid),显然我们只能取 (d_i geq mid) 的果汁。
    根据贪心的策略,我们肯定先取单价最小的果汁,用 (min(l_i,L)) 升体积做成混合果汁,需要 (p_i imes min(l_i,L)) 元的代价,如果还有剩余的体积就取单价第二小的果汁,如果还有就取第三小的,以此类推……
    然后我就死在了这个地方,还是太菜了啊 qwq(

    我们考虑以单价为下标建一棵权值线段树,每个节点上维护两个值,(sum) 表示价格在 ([l,r]) 区间中所有果汁的体积之和,(cst) 表示价格在 ([l,r]) 中所有果汁的单价与体积的乘积之和。
    每次我们从根节点开始,如果 (L) 不超过左子树的 (sum) 值,递归左子树,否则答案加上右子树的代价再递归右子树。
    由于 (mid) 值不确定,需要可持久化,时间复杂度 (nlog^2n)
    注意事项:需要判总体积是否 (geq L) 升。

    最后是代码:

    //Coded by tzc_wk
    /*
    数据不清空,爆零两行泪。
    多测不读完,爆零两行泪。
    边界不特判,爆零两行泪。
    贪心不证明,爆零两行泪。
    D P 顺序错,爆零两行泪。
    大小少等号,爆零两行泪。
    变量不统一,爆零两行泪。
    越界不判断,爆零两行泪。
    调试不注释,爆零两行泪。
    溢出不 l l,爆零两行泪。
    */
    #include <bits/stdc++.h>
    using namespace std;
    #define fi			first
    #define se			second
    #define fz(i,a,b)	for(int i=a;i<=b;i++)
    #define fd(i,a,b)	for(int i=a;i>=b;i--)
    #define foreach(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
    #define all(a)		a.begin(),a.end()
    #define giveup(...) return printf(__VA_ARGS__),0;
    #define fill0(a)	memset(a,0,sizeof(a))
    #define fill1(a)	memset(a,-1,sizeof(a))
    #define fillbig(a)	memset(a,0x3f,sizeof(a))
    #define fillsmall(a) memset(a,0xcf,sizeof(a))
    #define mask(a)		(1ll<<(a))
    #define maskx(a,x)	((a)<<(x))
    #define _bit(a,x)	(((a)>>(x))&1)
    #define _sz(a)		((int)(a).size())
    #define filei(a)	freopen(a,"r",stdin);
    #define fileo(a)	freopen(a,"w",stdout);
    #define fileio(a) 	freopen(a".in","r",stdin);freopen(a".out","w",stdout)
    #define eprintf(...) fprintf(stderr,__VA_ARGS__)
    #define put(x)		putchar(x)
    #define eoln        put('
    ')
    #define space		put(' ')
    #define y1			y_chenxiaoyan_1
    #define y0			y_chenxiaoyan_0
    #define int long long
    typedef pair<int,int> pii;
    inline int read(){
    	int x=0,neg=1;char c=getchar();
    	while(!isdigit(c)){
    		if(c=='-')	neg=-1;
    		c=getchar();
    	}
    	while(isdigit(c))	x=x*10+c-'0',c=getchar();
    	return x*neg;
    }
    inline void print(int x){
    	if(x<0){
    		putchar('-');
    		print(abs(x));
    		return;
    	}
    	if(x<=9)	putchar(x+'0');
    	else{
    		print(x/10);
    		putchar(x%10+'0');
    	}
    }
    inline int qpow(int x,int e,int _MOD){
    	int ans=1;
    	while(e){
    		if(e&1)	ans=ans*x%_MOD;
    		x=x*x%_MOD;
    		e>>=1;
    	}
    	return ans;
    }
    int n=read(),m=read();
    int key[100005],hs[100005],cntt;
    struct juice{
    	int d,p,l;
    	juice(){/*ycxakioi*/}
    	juice(int _d,int _p,int _l){
    		d=_d;p=_p;l=_l;
    	}
    	friend bool operator <(juice a,juice b){
    		return a.d<b.d;
    	}
    } a[100005];
    struct node{
    	int l,r,ch[2],sum,cst;
    } s[100005<<5];
    int ncnt=0,rt[100005];
    inline void build(int &k,int l,int r){
    	k=++ncnt;s[k].l=l;s[k].r=r;
    	if(l==r)	return;
    	int mid=(l+r)>>1;
    	build(s[k].ch[0],l,mid);
    	build(s[k].ch[1],mid+1,r);
    }
    inline void update(int &k,int pre,int p,int l){
    	k=++ncnt;s[k]=s[pre];
    	if(s[k].l==s[k].r){
    		s[k].sum+=l;
    		s[k].cst+=hs[p]*l;
    		return;
    	}
    	int mid=(s[k].l+s[k].r)>>1;
    	if(p<=mid)	update(s[k].ch[0],s[pre].ch[0],p,l);
    	else		update(s[k].ch[1],s[pre].ch[1],p,l);
    	s[k].sum=s[s[k].ch[0]].sum+s[s[k].ch[1]].sum;
    	s[k].cst=s[s[k].ch[0]].cst+s[s[k].ch[1]].cst;
    }
    inline bool check(int mid,int g,int l){
    	if(s[rt[mid]].sum<l)	return 0;
    	int cur=rt[mid];
    	while(1){
    		if(s[cur].l==s[cur].r){
    			g-=hs[s[cur].l]*l;
    			break;
    		}
    		if(l<=s[s[cur].ch[0]].sum){
    			cur=s[cur].ch[0];
    		}
    		else{
    			l-=s[s[cur].ch[0]].sum;
    			g-=s[s[cur].ch[0]].cst;
    			cur=s[cur].ch[1];
    		}
    	}
    	return g>=0;
    }
    signed main(){
    	fz(i,1,n)	a[i].d=read(),a[i].p=read(),a[i].l=read(),key[i]=a[i].p;
    	sort(key+1,key+n+1);
    	sort(a+1,a+n+1);
    	fz(i,1,n)	if(key[i]!=key[i-1])	hs[++cntt]=key[i];
    	fz(i,1,n)	a[i].p=lower_bound(hs+1,hs+cntt+1,a[i].p)-hs;
    	build(rt[n+1],1,cntt);
    	fd(i,n,1)	update(rt[i],rt[i+1],a[i].p,a[i].l);
    	a[0].d=-1;
    	while(m--){
    		int g=read(),l=read();
    		int L=1,R=n,ans=0;
    		while(L<=R){
    			int mid=(L+R)>>1;
    			if(check(mid,g,l))	ans=mid,L=mid+1;
    			else				R=mid-1;
    		}
    		cout<<a[ans].d<<endl;
    	}
    	return 0;
    }
    
  • 相关阅读:
    【转】禁用chrome firefox 的 WebRTC功能防止真实IP泄漏
    这是我的主场
    【转】反编译获取任何微信小程序源码(完)
    【转】npm 安装express npm ERR! code UNABLE_TO_VERIFY_LEAF_SIGNATURE
    查询最新的邮编地区
    【转】汇编语言入门教程
    Microsoft Windows远程桌面协议中间人攻击漏洞(CVE-2005-1794)漏洞解决方案(Windows server2003)
    IIS隐藏版本号教程(Windows Server 2003)
    Windows Server 2003添加防火墙策略教程
    Tomcat禁用SSLv3和RC4算法
  • 原文地址:https://www.cnblogs.com/ET2006/p/12729386.html
Copyright © 2011-2022 走看看