[CTSC2018]混合果汁

前言

先写思路后码代码,应该是对的,等我写完验证一下就知道了。

update 2021.4.6 写完了,一遍过。

题目

洛谷

讲解

我们先思考这样一个事情:如果规定一些果汁可以选,那么我们显然可以贪心选这些果汁中单价最少的判断是否可以满足一个小朋友的要求。

当然我们也可以将其放到线段树上,以价格为下标,查询的时候可以在线段树上二分。

显然我们要二分果汁美味度,以标记可以选的果汁有哪些,我们显然不能重新建树,为了保证时间复杂度,我们用主席树来动态维护前缀和。

多个小朋友?整体二分即可(似乎不用整体二分而直接做 \(m\) 次二分也行,只是常数稍微大了一点点)。

每个孩子在二分时最多会在主席树上查询 \(log_2n\) 次,时间复杂度应该是 \(O(n\log_2^2n)\) 级别。

代码

小常数!

struct Juice
{
	int d,p,l;//美味度 单价 上限 
	bool operator < (const Juice &px)const{
		return d < px.d;
	}
}s[MAXN];
struct Children
{
	LL g,L;
	int ID;
}c[MAXN],c2[MAXN];
int rt[MAXN];
struct PresidentTree
{
	int tot;
	struct node
	{
		int ch[2];
		LL P,V;//总价钱  总体积 
	}t[MAXN * 30];
	
	void Add(int lst,int &now,int l,int r,Juice ad)
	{
		now = ++tot;
		t[now] = t[lst];
		t[now].P += 1ll * ad.p * ad.l; 
		t[now].V += ad.l;
		if(l == r) return;
		int mid = (l+r) >> 1;
		if(ad.p <= mid) Add(t[lst].ch[0],t[now].ch[0],l,mid,ad);
		else Add(t[lst].ch[1],t[now].ch[1],mid+1,r,ad);
	}
	
	bool Query(int lst,int now,int l,int r,Children A)
	{
		if(t[now].V - t[lst].V < A.L) return 0;
		if(t[now].V - t[lst].V >= A.L && A.g >= t[now].P - t[lst].P) return 1;
		if(l == r) return A.g / l >= A.L;
		int mid = (l+r) >> 1;
		if(t[t[now].ch[0]].V - t[t[lst].ch[0]].V >= A.L) return Query(t[lst].ch[0],t[now].ch[0],l,mid,A);
		else if(t[t[now].ch[0]].P - t[t[lst].ch[0]].P > A.g) return 0;
		else 
		{
			A.g -= t[t[now].ch[0]].P - t[t[lst].ch[0]].P;
			A.L -= t[t[now].ch[0]].V - t[t[lst].ch[0]].V;
			return Query(t[lst].ch[1],t[now].ch[1],mid+1,r,A);
		}
	}
}pt;

void solve(int l,int r,int cl,int cr)
{
	int mid = (l+r) >> 1;
	int tot1 = cl,tot2 = 0;
	for(int i = cl;i <= cr;++ i)
	{
		if(pt.Query(rt[ef[mid]-1],rt[n],1,MAX,c[i])) ans[c[i].ID] = s[ef[mid]].d,c2[++tot2] = c[i];
		else c[tot1++] = c[i];
	}
	if(l == r) return;
	for(int i = 1;i <= tot2;++ i) c[tot1+i-1] = c2[i];
	solve(l,mid,cl,tot1-1); solve(mid+1,r,tot1,cr);
}

int main()
{

//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	n = Read(); m = Read();
	for(int i = 1;i <= n;++ i) s[i].d = Read(),s[i].p = Read(),s[i].l = Read(),MAX = Max(MAX,s[i].p);
	for(int i = 1;i <= m;++ i) c[i].g = Read(),c[i].L = Read(),c[i].ID = i;
	sort(s+1,s+n+1);
	for(int i = 1;i <= n;++ i) 
	{
		pt.Add(rt[i-1],rt[i],1,MAX,s[i]);
		if(s[i].d != s[i-1].d) ef[++nn] = i;
	}
	solve(1,nn,1,m);
	for(int i = 1;i <= m;++ i) Put(ans[i] ? ans[i] : -1,'\n');
	return 0;
}

后记

目前洛谷rk1。

posted @ 2021-04-04 22:06  皮皮刘  阅读(59)  评论(0编辑  收藏  举报