题面传送门

首先肯定将所有物品排个序。

考虑暴力做法,对于每个询问,枚举所有物品,能买就买。不过扫一眼就知道无法直接优化。

不妨换个角度,暴力做法是枚举询问,这次我们枚举物品。从左到右依次枚举所有物品,将所有买得起当前物品的询问答案 \(+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(平衡树+势能分析)的更多相关文章

  1. bzoj3211 花神游历各国 线段树,势能分析

    [bzoj3211]花神游历各国 2014年3月17日2,7230 Description   Input   Output 每次x=1时,每行一个整数,表示这次旅行的开心度 Sample Input ...

  2. BZOJ5312 冒险 势能分析、线段树

    传送门 区间位赋值.区间求最大值似乎是不能够像一般的线段树一样直接打标记的,但是直接暴力也太没有面子了. 我们考虑优化一下暴力:如果说线段树的一段区间内在当前修改的所有位置上所有数都是相同的,那么这个 ...

  3. Codeforces 679E - Bear and Bad Powers of 42(线段树+势能分析)

    Codeforces 题目传送门 & 洛谷题目传送门 这个 \(42\) 的条件非常奇怪,不过注意到本题 \(a_i\) 范围的最大值为 \(10^{14}\),而在值域范围内 \(42\) ...

  4. DZY Loves Colors CodeForces - 444C (线段树势能分析)

    大意:有$n$个格子, 初始$i$位置的颜色为$i$, 美丽值为0, 有两种操作 将区间$[l,r]$内的元素全部改为$x$, 每个元素的美丽值增加$|x-y|$, $y$为未改动时的值 询问区间$[ ...

  5. @codeforces - 702F@ T-Shirts

    目录 @description@ @solution@ @accepted code@ @details@ @description@ 有 n 件 T-shirt,第 i 件 T-shirt 有一个 ...

  6. 势能分析(splay分析)

    定义 第\(x\)次操作后,势能为\(\phi(x)\),该操作实际复杂度\(c(x)\),均摊复杂度\(a(x)\). 定义\(a(x)=c(x)+\phi(x)-\phi(x-1)\). 那么总复 ...

  7. Codeforces 420D Cup Trick 平衡树

    Cup Trick 平衡树维护一下位置. #include<bits/stdc++.h> #include <bits/extc++.h> #define LL long lo ...

  8. codeforces:855D Rowena Ravenclaw's Diadem分析和实现

    题目大意: 提供n个对象,分别编号为1,...,n.每个对象都可能是某个编号小于自己的对象的特例或是成分.认为某个对象的特例的特例依旧是该对象的特例,即特例关系传递,同样一个对象的成分的成分依旧是该对 ...

  9. [模板] 平衡树: Splay, 非旋Treap, 替罪羊树

    简介 二叉搜索树, 可以维护一个集合/序列, 同时维护节点的 \(size\), 因此可以支持 insert(v), delete(v), kth(p,k), rank(v)等操作. 另外, prev ...

随机推荐

  1. clock时钟

    ①时钟的偏移(skew):时钟分支信号在到达寄存器的时钟端口过程中,都存在有线网等延时,由于延时,到达寄存器时钟端口的时钟信号存在有相位差,也就是不能保证每一个沿都对齐,这种差异称为时钟偏移(cloc ...

  2. [敏捷软工团队博客]Beta阶段使用指南

    软件工程教学实践平台使用指南 项目地址:http://20.185.223.195:8000/ 项目团队:the agiles 进入界面如图: 目录 软件工程教学实践平台使用指南 学生端 登录 iss ...

  3. Zabbix 5.0:监控阿里云RDS

    Blog:博客园 个人 由于近期压测,需要频繁登录阿里云查看RDS监控,每次登录查看监控步骤较为繁琐,故将监控接入到zabbix. 概述 由于阿里云已做了RDS的监控,我们只需要通过阿里云SDK把这些 ...

  4. Noip模拟35 2021.8.10

    考试题目变成四道了,貌似确实根本改不完... 不过给了两个小时颓废时间确实很爽(芜湖--) 但是前几天三道题改着不是很费劲的时候为什么不给放松时间, 非要在改不完题的时候颓?? 算了算了不碎碎念了.. ...

  5. Spark面试题(二)

    首发于我的个人博客:Spark面试题(二) 1.Spark有哪两种算子? Transformation(转化)算子和Action(执行)算子. 2.Spark有哪些聚合类的算子,我们应该尽量避免什么类 ...

  6. 线路由器频段带宽是是20M好还是40M好

    无线路由器频段带宽还是40M好. 40M的信号强,速度快.   1.20MHz在11n的情况下能达到144Mbps带宽.穿透性不错.传输距离较远 40MHz在11n的情况下能达到300Mbps带宽.穿 ...

  7. Linux多线程编程实例解析

    Linux系统下的多线程遵循POSIX线程接口,称为 pthread.编写Linux下的多线程程序,需要使用头文件pthread.h,连接时需要使用库libpthread.a.顺便说一下,Linux ...

  8. 转:bash shell 语法1

    1 Shell介绍 Shell的作用是解释执行用户的命令,用户输入一条命令,Shell就解释执行一条,这种方式称为交互式(Interactive),Shell还有一种执行命令的方式称为批处理(Batc ...

  9. Luogu P2024 [NOI2001]食物链 | 并查集

    题目链接 思路:并查集,因为一开始我们并不知道每一只动物是哪一个种类的,所以我们干脆建立三倍于n的空间,1~n这三分之一用来存第i只动物是A的情况,n+1~2n这三分之一用来存第(i-n)只动物是B的 ...

  10. cm0 逆向分析

    目录 cm0 逆向分析 前言 Strings工具复习 String工具使用说明 Strings工具解cm0题 cm0 逆向分析 前言 Emmmmm,我假装你看到这里已经学过了我的<恶意代码分析实 ...