• 【CF702F】T-Shirts


    题目

    题目链接:https://codeforces.com/contest/702/problem/F
    (n) 种T恤,每种有价格 (c_i) 和品质 (q_i)
    (m) 个人要买 (T) 恤,第 (i) 个人有 (v_i) 元,每人每次都会买一件能买得起的 (q_i) 最大的T恤。一个人只能买一种T恤一件,所有人之间都是独立的。
    问最后每个人买了多少件 (T) 恤?如果有多个 (q_i) 最大的T恤,会从价格低的开始买。
    (n,mleq 2 imes 10^5)

    思路

    可以先把所有物品排序,如果把每一个人分别考虑复杂度显然是无法优化的。
    所以我们换一个角度考虑,维护每一个人剩余的钱,然后枚举每一件衣服,把剩余的钱不小于衣服价格的人的钱全部减去衣服价格。
    这样看起来就可以用数据结构维护了。我们需要支持把超过 (c) 的部分减去 (c) 的操作。但是如果每次暴力把超过 (c) 的部分一个一个减去,复杂度依然爆炸。
    根据价格 (c) 把所有人分成三部分:剩余的钱在 ([0,c))([c,2c])((2c,+infty)) 的。其中第一部分不需要操作,第三部分需要支持区间打标记,第二部分就只能暴力减。
    考虑维护一棵 FHQ Treap。这样就可以轻松的把三个部分划出来,并且支持取件打标记或者暴力减。考虑到第二部分每一个数减去 (c) 后至少都除以了 (2),所以每一个数字最多只会被暴力减 (O(log a)) 次,这样暴力插入的复杂度就是 (O(nlog^2m)) 的了。
    具体实现时先把三个部分拿出来,然后给第三部分全部打上钱减 (c),买的衣服 (+1) 的两个标记,然后与第一部分合并(显然第三部分全部减去 (c) 后每一个人的钱都>第一部分的钱),最后把第二部分依次插入即可。
    时间复杂度 (O(nlog^2 m))

    代码

    #include <bits/stdc++.h>
    #define random (rand()*32768+rand())
    using namespace std;
    
    const int N=200010;
    int n,m,rt,ans[N];
    
    struct node
    {
    	int c,q;
    }a[N];
    
    bool cmp(node x,node y)
    {
    	return (x.q==y.q) ? (x.c<y.c) : (x.q>y.q);
    }
    
    struct FHQTreap
    {
    	int val[N],cnt[N],lazy[N][2],dat[N],ch[N][2];
    	
    	void pushdown(int x)
    	{
    		int lc=ch[x][0],rc=ch[x][1];
    		if (lazy[x][0])
    		{
    			cnt[lc]+=lazy[x][0]; lazy[lc][0]+=lazy[x][0];
    			cnt[rc]+=lazy[x][0]; lazy[rc][0]+=lazy[x][0];
    			lazy[x][0]=0;
    		}
    		if (lazy[x][1])
    		{
    			val[lc]-=lazy[x][1]; lazy[lc][1]+=lazy[x][1];
    			val[rc]-=lazy[x][1]; lazy[rc][1]+=lazy[x][1];
    			lazy[x][1]=0;
    		}
    	}
    	
    	void split(int x,int k,int &lc,int &rc)
    	{
    		if (!x) return (void)(lc=rc=0);
    		pushdown(x);
    		if (val[x]<=k)
    			lc=x,split(ch[x][1],k,ch[x][1],rc);
    		else
    			rc=x,split(ch[x][0],k,lc,ch[x][0]);
    	}
    	
    	int merge(int x,int y)
    	{
    		if (!x || !y) return x+y;
    		pushdown(x); pushdown(y);
    		if (dat[x]<dat[y])
    			return ch[x][1]=merge(ch[x][1],y),x;
    		else
    			return ch[y][0]=merge(x,ch[y][0]),y;
    	}
    	
    	void ins(int x,int v)
    	{
    		int y,z;
    		val[x]=v; dat[x]=random;
    		split(rt,v,y,z);
    		rt=merge(merge(y,x),z);
    	}
    	
    	void dfs(int x,int &y,int c,bool flag)
    	{
    		pushdown(x);
    		if (ch[x][0]) dfs(ch[x][0],y,c,flag);
    		if (ch[x][1]) dfs(ch[x][1],y,c,flag);
    		if (flag)
    		{
    			int z;
    			val[x]-=c; cnt[x]++; ch[x][0]=ch[x][1]=0;
    			split(y,val[x],y,z);
    			y=merge(merge(y,x),z);
    		}
    	}
    }fhq;
    
    int main()
    {
    	srand(123123);	
    	scanf("%d",&n);
    	for (int i=1;i<=n;i++)
    		scanf("%d%d",&a[i].c,&a[i].q);
    	scanf("%d",&m);
    	for (int i=1,x;i<=m;i++)
    	{
    		scanf("%d",&x);
    		fhq.ins(i,x);
    	}
    	sort(a+1,a+1+n,cmp);
    	for (int i=1;i<=n;i++)
    	{
    		int x,y,z,c=a[i].c;
    		fhq.split(rt,c-1,x,y); fhq.split(y,c*2,y,z);
    		
    		fhq.cnt[z]++; fhq.lazy[z][0]++;
    		fhq.val[z]-=c; fhq.lazy[z][1]+=c;
    		rt=fhq.merge(x,z);
    		
    		fhq.dfs(y,rt,c,1);
    	}
    	fhq.dfs(rt,n,0,0);
    	for (int i=1;i<=m;i++)
    		printf("%d ",fhq.cnt[i]);
    	return 0;
    } 
    
  • 相关阅读:
    关于COM+的一些回顾
    Workflow Foundation 4.0中的事件驱动流程设计和应用(四)
    html5及其相关学习资源介绍
    ADO.NET Data Service如何直接支持用Json格式返回数据
    《实践与思考》系列连载(5)——问答Hprose,以及关于技术与开源的思考
    .NET Framework 4新特性之 Type Equivalence(等价类型)
    做软件也是要有点追求的
    Console的默认Encoding问题
    《实践与思考》系列连载(6)——IT从业人员工作环境及状态调查 抽奖结果公布
    Workflow Foundation 4.0中的事件驱动流程设计和应用(一)
  • 原文地址:https://www.cnblogs.com/stoorz/p/14735850.html
Copyright © 2020-2023  润新知