[Codeforces702F]T-Shirts——非旋转treap+贪心
题目链接:
题目大意:有$n$种T恤,每种有一个价格$c_{i}$和品质$q_{i}$且每种数量无限。现在有$m$个人,第$i$个人有$v_{i}$元,每人每次会买他能买得起的品质最高的一件T恤(当两件T恤品质相同时优先买价格低的),每人只能买一件每种T恤。求最后每个人买的T恤件数。
暴力的方法是将T恤品质从大到小排序,对于每个人从第一种T恤(排序后的第一种)开始模拟每件T恤,能买就买,不能买就跳过。
发现暴力的方法是对于每个人决策每件T恤,我们可以对于每件T恤来决策哪些人能买,用非旋转$treap$来维护每个人还剩的钱数。
那么每次就是将权值大于$q_{i}$的人的权值都减少$q_{i}$并把答案都增加$1$。
对于区间修改我们直接打标记即可,但问题是无法将被修改的部分和没被修改的部分合并。
因为非旋转$treap$的合并要求一棵树的最大权值小于另一棵树的最小权值,而被修改部分在权值减小之后会有一部分的权值比未被修改部分最大权值小。
那么我们就把这部分暴力插入到未被修改的那棵树中,剩下被修改的那部分直接合并。
假设被暴力插入的权值为$x$,那么$x-q_{i}<q_{i},x>=q_{i}$,也就是说$2q_{i}>x,q_{i}>\frac{x}{2}$,即每次暴力插入的数权值减半,所以每个数最多暴力插入$log_{v_{i}}$次。
总时间复杂度是$O((n+\sum log_{v_{i}})log_{m})$。
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<bitset>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
int ls[200010];
int rs[200010];
int val[200010];
int num[200010];
int r[200010];
int sum[200010];
int tag[200010];
int res[200010];
int root;
int n,m,x;
int cnt;
int a,b,c,d;
int L,R;
struct lty
{
int c,v;
}q[200010];
queue<int>Q;
inline int build(int v)
{
int rt=++cnt;
r[rt]=rand();
val[rt]=v;
return rt;
}
inline void add(int rt,int x,int y)
{
tag[rt]+=x;
val[rt]+=x;
sum[rt]+=y;
res[rt]+=y;
}
inline void pushdown(int rt)
{
if(tag[rt]&&sum[rt])
{
add(ls[rt],tag[rt],sum[rt]);
add(rs[rt],tag[rt],sum[rt]);
tag[rt]=sum[rt]=0;
}
}
inline int merge(int x,int y)
{
if(!x||!y)
{
return x+y;
}
pushdown(x);
pushdown(y);
if(r[x]<r[y])
{
rs[x]=merge(rs[x],y);
return x;
}
else
{
ls[y]=merge(x,ls[y]);
return y;
}
}
inline void split(int rt,int &x,int &y,int k)
{
if(!rt)
{
x=y=0;
return ;
}
pushdown(rt);
if(val[rt]>=k)
{
y=rt;
split(ls[rt],x,ls[y],k);
}
else
{
x=rt;
split(rs[rt],rs[x],y,k);
}
}
inline bool cmp(lty a,lty b)
{
return a.v==b.v?a.c<b.c:a.v>b.v;
}
inline void dfs(int rt)
{
pushdown(rt);
if(ls[rt])
{
dfs(ls[rt]);
}
if(rs[rt])
{
dfs(rs[rt]);
}
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&q[i].c,&q[i].v);
}
sort(q+1,q+1+n,cmp);
scanf("%d",&m);
for(int i=1;i<=m;i++)
{
scanf("%d",&x);
split(root,a,b,x);
root=merge(merge(a,build(x)),b);
}
for(int i=1;i<=n;i++)
{
split(root,a,b,q[i].c);
split(b,b,c,2*q[i].c);
add(b,-q[i].c,1);
add(c,-q[i].c,1);
Q.push(b);
while(!Q.empty())
{
int now=Q.front();
Q.pop();
pushdown(now);
if(ls[now])
{
Q.push(ls[now]);
}
if(rs[now])
{
Q.push(rs[now]);
}
ls[now]=rs[now]=0;
split(a,a,d,val[now]);
a=merge(merge(a,now),d);
}
root=merge(a,c);
}
dfs(root);
for(int i=1;i<=m;i++)
{
printf("%d ",res[i]);
}
}
[Codeforces702F]T-Shirts——非旋转treap+贪心的更多相关文章
- [bzoj3173]最长上升子序列_非旋转Treap
最长上升子序列 bzoj-3173 题目大意:有1-n,n个数,第i次操作是将i加入到原有序列中制定的位置,后查询当前序列中最长上升子序列长度. 注释:1<=n<=10,000,开始序列为 ...
- 关于非旋转treap的学习
非旋转treap的操作基于split和merge操作,其余操作和普通平衡树一样,复杂度保证方式与旋转treap差不多,都是基于一个随机的参数,这样构出的树树高为\(logn\) split 作用:将原 ...
- BZOJ5063旅游——非旋转treap
题目描述 小奇成功打开了大科学家的电脑. 大科学家打算前往n处景点旅游,他用一个序列来维护它们之间的顺序.初 始时,序列为1,2,...,n. 接着,大科学家进行m次操作来打乱顺序.每次操作有6步: ...
- BZOJ3223文艺平衡树——非旋转treap
此为平衡树系列第二道:文艺平衡树您需要写一种数据结构,来维护一个有序数列,其中需要提供以下操作: 翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 ...
- BZOJ3224普通平衡树——非旋转treap
题目: 此为平衡树系列第一道:普通平衡树您需要写一种数据结构,来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3. 查询x数的排名(若有多个相同的数, ...
- [NOIP]2017列队——旋转treap/非旋转treap
Sylvia 是一个热爱学习的女孩子. 前段时间,Sylvia 参加了学校的军训.众所周知,军训的时候需要站方阵. Sylvia所在的方阵中有n × m名学生,方阵的行数为 n,列数为m. 为了便 ...
- BZOJ3729Gty的游戏——阶梯博弈+巴什博弈+非旋转treap(平衡树动态维护dfs序)
题目描述 某一天gty在与他的妹子玩游戏.妹子提出一个游戏,给定一棵有根树,每个节点有一些石子,每次可以将不多于L的石子移动到父节点,询问将某个节点的子树中的石子移动到这个节点先手是否有必胜策略.gt ...
- BZOJ1552[Cerc2007]robotic sort&BZOJ3506[Cqoi2014]排序机械臂——非旋转treap
题目描述 输入 输入共两行,第一行为一个整数N,N表示物品的个数,1<=N<=100000. 第二行为N个用空格隔开的正整数,表示N个物品最初排列的编号. 输出 输出共一行,N个用空格隔开 ...
- BZOJ1251序列终结者——非旋转treap
题目描述 网上有许多题,就是给定一个序列,要你支持几种操作:A.B.C.D.一看另一道题,又是一个序列 要支持几种操作:D.C.B.A.尤其是我们这里的某人,出模拟试题,居然还出了一道这样的,真是没技 ...
随机推荐
- 诗人般的机器学习,ML工作原理大揭秘
诗人般的机器学习,ML工作原理大揭秘 https://mp.weixin.qq.com/s/7N96aPAM_M6t0rV0yMLKbg 选自arXiv 作者:Cassie Kozyrkov 机器之心 ...
- iOS-----------关于UDID
最近看友盟的SDK更新日志:(设备系统的正常升级不会改变OpenUDID) Apple公司于2013年5月1日开始,拒绝采集UDID的App上架App Store. 为适应Apple公司的这一政策,2 ...
- pthread_exit在main线程中的用处
在main线程中调用pthread_exit会起到只让main线程退出,但是保留进程资源,供其他由main创建的线程使用,直至所有线程都结束,但在其他线程中不会有这种效果 https://stacko ...
- 五、RemoteViews
RemoteViews表示的是一个View结构,它可以在其他进程中显示.RemoteViews在Android中的使用场景有两种:通知栏和桌面小部件. 1.RemoteViews的应用 RemoteV ...
- SQL学习笔记---常用命令
常用命令 变量 1.声明 declare @变量名 类型,… 2.赋值 1.同时赋值多个变量(可以结合查询) select @变量名=表达式1,表达式2 2.单个赋值(推荐) set @变量名=表达式 ...
- dynalist 配额
2018-8-29 dynalist 配额 提示有一个G的配额 就是使用的流量用光了.仅有1个G
- MySQL的Limit详解
问题:数据库查询语句,如何只返回一部分数据? Top子句 TOP 子句用于规定要返回的记录的数目.对于拥有数千条记录的大型表来说,TOP 子句是非常有用的. 在SQL Server数据库中语法为: S ...
- docker容器日志收集方案(方案三 filebeat+journald本地日志收集)
其实方案三和方案二日志采集套路一样,但是还是有点差别. 差别就在于日志格式如下: 为了方便对比吧日志贴上来 Nov 16 10:51:58 localhost 939fe968a91d[4721] ...
- 【Python使用】使用pip安装卸载Python包(含离线安装Python包)未完成???
pip 是 Python 包管理工具,该工具提供了对Python包的查找.下载.安装.卸载的功能.Python 2.7.9 + 或 Python 3.4+ 以上版本都自带 pip 工具. pip使用( ...
- Python开发【内置模块篇】
动态导入模块 动态导入模块 导入一个库名为字符串的 module_t = __import__('m1.t') print (module_t) #m1 import importlib m=impo ...