【CTSC2018】混合果汁

【CTSC2018】混合果汁

下周就省选了,好虚啊

解析:

首先第一眼看到这道题就有个nm再带log的做法,就是直接二分就行了

然后我们发现这样的话没有把他给你的果汁的信息利用起来,所以我们直接对果汁按美味度排个序,套个主席树,再二分就做完了

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll inf=2e18;
const int N=1e5+10;
struct node{
	ll sl,g;
	int l,r;
};
node tree[N<<7];
struct v_d{
	ll d,p,l;
};
v_d v[N];
int root[N];
int n,m,d_max,cnt;
ll g,l;
bool cmp(v_d x,v_d y){
	return x.d>y.d;
}
ll pan(ll x,ll y)
{
	if (x==inf||y==inf) return inf;
	if (x+y>1e18) return inf;
	else return x+y;
}
void build(int l,int r,int k)
{
	cnt=max(cnt,k);
	if (l==r) return;
	else {
		int mid=(l+r)/2;
		tree[k].l=(k<<1); tree[k].r=(k<<1|1);
		build(l,mid,k<<1);
		build(mid+1,r,k<<1|1);
	}
}
void update(int x)
{
	tree[x].sl=tree[tree[x].l].sl+tree[tree[x].r].sl;
	tree[x].g=pan(tree[tree[x].l].g,tree[tree[x].r].g);
}
void lalala(int nowr,int now,int l,int r,v_d x)
{
	if (l==r) {
		tree[now].sl=tree[nowr].sl+x.l;
		tree[now].g=pan(tree[nowr].g,x.l*x.p);
	}
	else {
		int mid=(l+r)/2;
		if (x.p<=mid) {
			tree[now].r=tree[nowr].r; tree[now].l=++cnt; lalala(tree[nowr].l,tree[now].l,l,mid,x);
		}
		else {
			tree[now].l=tree[nowr].l; tree[now].r=++cnt; lalala(tree[nowr].r,tree[now].r,mid+1,r,x);
		}
		update(now);
	}
}
bool pan1(int x,int l,int r,ll g,ll lim)
{
     if (lim>tree[x].sl) return 0;
     if (lim==tree[x].sl) return (g>=tree[x].g);
     if (l==r) return (g>=(ll)l*lim);
     int mid=(l+r)/2;
     if (tree[tree[x].l].sl<lim) {
     	g-=tree[tree[x].l].g;
     	if (g<=0) return 0;
     	return pan1(tree[x].r,mid+1,r,g,lim-tree[tree[x].l].sl);
     } 
     else return pan1(tree[x].l,l,mid,g,lim);
}
ll findans(int l,int r,ll g,ll lim)
{
	if (l>r) return inf;
    int mid=(l+r)/2;
    if (pan1(root[mid],1,d_max,g,lim)) return min((ll)mid,findans(l,mid-1,g,lim));
    else return findans(mid+1,r,g,lim);
}
int main()
{
	scanf("%d%d",&n,&m);
	d_max=0;
	for (int i=1;i<=n;i++) {
		scanf("%lld%lld%lld",&v[i].d,&v[i].p,&v[i].l);
		d_max=max(d_max,(int)v[i].p);
	}
	sort(v+1,v+n+1,cmp);
	root[0]=1;
	build(1,d_max,1);
	for (int i=1;i<=n;i++) {
		root[i]=++cnt;
		lalala(root[i-1],root[i],1,d_max,v[i]);
	} 
	for (int i=1;i<=m;i++){
		scanf("%lld%lld",&g,&l);
		ll s=findans(1,n,g,l);
		if (s==inf) printf("%d\n",-1);
		else
		printf("%lld\n",v[s].d);
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值