Codeforces 702F - T-shirts(平衡树+势能分析)
首先肯定将所有物品排个序。
考虑暴力做法,对于每个询问,枚举所有物品,能买就买。不过扫一眼就知道无法直接优化。
不妨换个角度,暴力做法是枚举询问,这次我们枚举物品。从左到右依次枚举所有物品,将所有买得起当前物品的询问答案 \(+1\),钱数减去当前物品的价格。这样就貌似与 DS 能够搭得上边了。
于是题目变为:\(n\) 次操作,每次操作将序列所有值 \(\geq c\) 的数减去 \(c\),问每个数被操作了几次。
可还是不好维护啊,平衡树 split 出 \(\geq c\) 的数后你还是要暴力修改啊。
这时候我们就需要用到一种奇淫技巧,学名“势能分析”(咋感觉像物理内容啊qwq)
我们将原序列 split 成三个部分,\([1,c),[c,2c),[2c,\infty)\),显然,第一部分不会被操作,第三部分被操作后相对位置不会发生变化,因此我们只需暴力修改第二部分。
你可能会直觉地认为这样子优化没啥卵用,其实这样做复杂度反倒是对的。
这样看似不起眼的优化为什么就把不可能变成可能了呢?
注意到,我们暴力修改的数都在 \([c,2c)\) 中,也就是修改完之后,原数至多变为原来的一半。也就是说每个数最多被修改 \(\log c_i\) 次,总复杂度线性对数方,可以通过四秒时限。
#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 ffe(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,63,sizeof(a))
#define pb push_back
#define ppb pop_back
#define mp make_pair
template<typename T1,typename T2> void chkmin(T1 &x,T2 y){if(x>y) x=y;}
template<typename T1,typename T2> void chkmax(T1 &x,T2 y){if(x<y) x=y;}
typedef pair<int,int> pii;
typedef long long ll;
template<typename T> void read(T &x){
char c=getchar();T neg=1;
while(!isdigit(c)){if(c=='-') neg=-1;c=getchar();}
while(isdigit(c)) x=x*10+c-'0',c=getchar();
x*=neg;
}
const int MAXN=2e5+5;
int Rand(){return rand()<<15|rand();}
int n,m,ans[MAXN+5];
struct event{int c,q;} a[MAXN+5];
bool cmp(event x,event y){if(x.q!=y.q) return x.q>y.q;return x.c<y.c;}
struct node{
int ch[2],id,val,key,cntlz,minlz,cnt;
} s[MAXN+5];
int ncnt=0,rt=0;
void pushdown(int k){
if(s[k].minlz){
if(s[k].ch[0]) s[s[k].ch[0]].minlz+=s[k].minlz,s[s[k].ch[0]].val-=s[k].minlz;
if(s[k].ch[1]) s[s[k].ch[1]].minlz+=s[k].minlz,s[s[k].ch[1]].val-=s[k].minlz;
s[k].minlz=0;
} if(s[k].cntlz){
if(s[k].ch[0]) s[s[k].ch[0]].cntlz+=s[k].cntlz,s[s[k].ch[0]].cnt+=s[k].cntlz;
if(s[k].ch[1]) s[s[k].ch[1]].cntlz+=s[k].cntlz,s[s[k].ch[1]].cnt+=s[k].cntlz;
s[k].cntlz=0;
}
}
void split(int k,int val,int &a,int &b){
if(!k){a=b=0;return;} pushdown(k);
if(s[k].val<=val) a=k,split(s[k].ch[1],val,s[k].ch[1],b);
else b=k,split(s[k].ch[0],val,a,s[k].ch[0]);
}
int merge(int x,int y){
if(!x||!y) return x|y;pushdown(x);pushdown(y);
if(s[x].key<s[y].key) return s[x].ch[1]=merge(s[x].ch[1],y),x;
else return s[y].ch[0]=merge(x,s[y].ch[0]),y;
}
void dfsins(int x,int &y,int z){//insert all nodes in subtree x into subtree y, val-=z
if(!x) return;pushdown(x);
dfsins(s[x].ch[0],y,z);dfsins(s[x].ch[1],y,z);
s[x].ch[0]=s[x].ch[1]=0;s[x].val-=z;s[x].cnt++;
int k1,k2;split(y,s[x].val,k1,k2);y=merge(merge(k1,x),k2);
}
void insert(int x,int id){
int k1,k2;split(rt,x,k1,k2);
ncnt++;s[ncnt].id=id;s[ncnt].key=Rand();s[ncnt].val=x;
rt=merge(merge(k1,ncnt),k2);
}
void dfscalc(int x){
if(!x) return;pushdown(x);
ans[s[x].id]=s[x].cnt;dfscalc(s[x].ch[0]);dfscalc(s[x].ch[1]);
}
int main(){
srand(19260817);scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d%d",&a[i].c,&a[i].q);
sort(a+1,a+n+1,cmp);scanf("%d",&m);
for(int i=1;i<=m;i++){int x;scanf("%d",&x);insert(x,i);}
for(int i=1;i<=n;i++){
int k1,k2,k3;split(rt,a[i].c-1,k1,k2);split(k2,a[i].c<<1,k2,k3);
if(k3){s[k3].val-=a[i].c;s[k3].cnt++;s[k3].minlz+=a[i].c;s[k3].cntlz++;}
dfsins(k2,k1,a[i].c);rt=merge(k1,k3);
}
for(int i=1;i<=m;i++) ans[s[i].id]=s[i].cnt;
dfscalc(rt);for(int i=1;i<=m;i++) printf("%d ",ans[i]);
return 0;
}
Codeforces 702F - T-shirts(平衡树+势能分析)的更多相关文章
- bzoj3211 花神游历各国 线段树,势能分析
[bzoj3211]花神游历各国 2014年3月17日2,7230 Description Input Output 每次x=1时,每行一个整数,表示这次旅行的开心度 Sample Input ...
- BZOJ5312 冒险 势能分析、线段树
传送门 区间位赋值.区间求最大值似乎是不能够像一般的线段树一样直接打标记的,但是直接暴力也太没有面子了. 我们考虑优化一下暴力:如果说线段树的一段区间内在当前修改的所有位置上所有数都是相同的,那么这个 ...
- Codeforces 679E - Bear and Bad Powers of 42(线段树+势能分析)
Codeforces 题目传送门 & 洛谷题目传送门 这个 \(42\) 的条件非常奇怪,不过注意到本题 \(a_i\) 范围的最大值为 \(10^{14}\),而在值域范围内 \(42\) ...
- DZY Loves Colors CodeForces - 444C (线段树势能分析)
大意:有$n$个格子, 初始$i$位置的颜色为$i$, 美丽值为0, 有两种操作 将区间$[l,r]$内的元素全部改为$x$, 每个元素的美丽值增加$|x-y|$, $y$为未改动时的值 询问区间$[ ...
- @codeforces - 702F@ T-Shirts
目录 @description@ @solution@ @accepted code@ @details@ @description@ 有 n 件 T-shirt,第 i 件 T-shirt 有一个 ...
- 势能分析(splay分析)
定义 第\(x\)次操作后,势能为\(\phi(x)\),该操作实际复杂度\(c(x)\),均摊复杂度\(a(x)\). 定义\(a(x)=c(x)+\phi(x)-\phi(x-1)\). 那么总复 ...
- Codeforces 420D Cup Trick 平衡树
Cup Trick 平衡树维护一下位置. #include<bits/stdc++.h> #include <bits/extc++.h> #define LL long lo ...
- codeforces:855D Rowena Ravenclaw's Diadem分析和实现
题目大意: 提供n个对象,分别编号为1,...,n.每个对象都可能是某个编号小于自己的对象的特例或是成分.认为某个对象的特例的特例依旧是该对象的特例,即特例关系传递,同样一个对象的成分的成分依旧是该对 ...
- [模板] 平衡树: Splay, 非旋Treap, 替罪羊树
简介 二叉搜索树, 可以维护一个集合/序列, 同时维护节点的 \(size\), 因此可以支持 insert(v), delete(v), kth(p,k), rank(v)等操作. 另外, prev ...
随机推荐
- 【Java虚拟机6】Java内存模型(Java篇)
什么是Java内存模型 <Java虚拟机规范>中曾试图定义一种"Java内存模型"(Java Memory Model,JMM)来屏蔽各种硬件和操作系统的内存访问差异, ...
- nssm.exe使用方法
nssm no-sucking service manager 1. 安装服务命令 nssm install <servicename> nssm install <servicen ...
- 论文解读丨表格识别模型TableMaster
摘要:在此解决方案中把表格识别分成了四个部分:表格结构序列识别.文字检测.文字识别.单元格和文字框对齐.其中表格结构序列识别用到的模型是基于Master修改的,文字检测模型用到的是PSENet,文字识 ...
- [敏捷软工团队博客]Beta设计和计划
项目 内容 2020春季计算机学院软件工程(罗杰 任健) 博客园班级博客 作业要求 Beta设计和计划 我们在这个课程的目标是 在团队合作中锻炼自己 这个作业在哪个具体方面帮助我们实现目标 对Beta ...
- Linux线程互斥学习笔记--详细分析
一.互斥锁 为啥要有互斥? 多个进程/线程执行的先后顺序不确定,何时切出CPU也不确定. 多个进程/线程访问变量的动作往往不是原子的. 1. 操作步骤 (1)创建锁 // 创建互斥锁mutex pth ...
- linux Segmentation faults 段错误详解
什么是段错误 下面是来自 Answers.com 的定义: A segmentation fault (often shortened to segfault) is a particular err ...
- 『学了就忘』Linux基础命令 — 25、文件基本权限的管理
目录 1.文件和目录的默认权限 2.umask默认权限 (1)查看系统的umask权限 (2)用八进制数值显示umask权限 (3)umask权限的计算方法 (4)注意:umask默认权限的计算绝不是 ...
- 热门剧本杀与 SaaS 的不解之缘
近年来,"剧本杀"这种以剧本为核心,玩家分别扮演不同角色推理案情找出真凶的娱乐项目在年轻人的范围内迅速传开,已悄然形成了一个市场规模超百亿的新兴产业,吸引了大量淘金者.而在互联网时 ...
- 【AI测试】人工智能 (AI) 测试--第二篇
测试用例 人工智能 (AI) 测试 或者说是 算法测试,主要做的有三件事. 收集测试数据 思考需要什么样的测试数据,测试数据的标注 跑测试数据 编写测试脚本批量运行 查看数据结果 统计正确和错误的个数 ...
- JDK 之 Arrays.asList - 源码分析
Arrays工具类提供了一个方法asList, 使用该方法可以将一个变长参数或者数组转换成List . 其源代码如下: @SafeVarargs public static <T> Lis ...