洛谷P3285 [SCOI2014]方伯伯的OJ 动态开点平衡树
洛谷P3285 [SCOI2014]方伯伯的OJ 动态开点平衡树
题目描述
方伯伯正在做他的 \(Oj\) 。现在他在处理 \(Oj\) 上的用户排名问题。 \(Oj\) 上注册了 \(n\) 个用户,编号为 \(1 \sim n\),一开始他们按照编号排名。
方伯伯会按照心情对这些用户做以下四种操作,修改用户的排名和编号:
\(1\).操作格式为 \(1\ x\ y\),意味着将编号为$ x$ 的用户编号改为 \(y\) ,而排名不变,执行完该操作后需要输出该用户在队列中的位置,数据保证 \(x\) 必然出现在队列中,同时,\(y\) 是一个当前不在排名中的编号。
\(2\).操作格式为\(2\ x\),意味着将编号为 \(x\) 的用户的排名提升到第一位,执行完该操作后需要输出执行该操作前编号为 \(x\) 用户的排名。
\(3\).操作格式为 \(3\ x\) ,意味着将编号为 \(x\) 的用户的排名降到最后一位,执行完该操作后需要输出执行该操作前编号为 \(x\) 用户的排名。
4.操作格式为 \(4\ k\),意味着查询当前排名为 \(k\) 的用户编号,执行完该操作后需要输出当前操作用户的编号。
但同时为了防止别人监听自己的工作,方伯伯对他的操作进行了加密,即将四种操作的格式分别改为了:
- \(1\ x+a\ y+a\)
- \(2\ x+a\)
- \(3\ x+a\)
- \(4\ k+a\)
其中 \(a\) 为上一次操作得到的输出,一开始 \(a=0\)。
例如:上一次操作得到的输出是 \(5\) 这一次操作的输入为:\(1\ 13\ 15\)
因为这个输入是经过加密后的,所以你应该处理的操作是 \(1\ 8\ 10\)
现在你截获了方伯伯的所有操作,希望你能给出结果。
输入输出格式
输入格式
输入的第 \(1\) 行包含 \(2\) 个用空格分隔的整数 \(n\) 和 \(m\) ,表示初始用户数和操作数。此后有 \(m\) 行,每行是一个询问,询问格式如上所示。
输出格式
输出包含 \(m\) 行。每行包含一个整数,其中第 \(i\) 行的整数表示第 \(i\) 个操作的输出。
输入输出样例
输入样例 #1
10 10
1 2 11
3 13
2 5
3 7
2 8
2 10
2 11
3 14
2 18
4 9
输出样例 #1
2
2
2
4
3
5
5
7
8
11
说明
对于 \(100\%\) 的数据,\(1 \leq n \leq 10^8\),\(1 \leq m \leq 10^5\)
输入保证对于所有的操作 \(1\),\(2\),\(3\),\(x\) 必然已经出现在队列中,同时对于所有操作 \(1\),\(1 <= y <= 2 \times 10^8\),并且 \(y\) 没有出现在队列中。
对于所有操作 \(4\),保证 \(1 \leq k \leq n\)。
分析
无旋 \(treap\) 按照 \(siz\) 分裂可以维护序列上的信息
暴力的做法是把 \(1 \sim n\) 中的每一个数都扔到平衡树中
对于每一个数,用一个数组记录一下它在平衡树上对应的是哪一个节点
对于操作 \(1\),只需要把 \(x\) 在平衡树上所代表的节点分裂出来,然后把当前节点的权值改为 \(y\),再合并回去即可
对于操作 \(2\),通过一个函数 \(getrk(x)\) 查找平衡树上编号为 \(x\) 的节点在序列中的位置
具体的实现就是一直跳父亲,如果当前节点是父亲节点的右儿子,那么将左儿子和父亲节点的 \(siz\) 累加
父亲的信息在 \(pushup\) 的时候更新,而且在进入 \(merge\) 和 \(split\) 的时候要把当前节点的父亲节点置为 \(0\)
找到排名之后把当前的节点和排名在它前面的节点都 \(split\) 出来,交换一下位置再合并回去即可
操作 \(3\) 同理
对于操作 \(4\),从根节点开始在平衡树上二分查找即可
但是 \(n\) 的范围达到了 \(1e8\),这样做复杂度肯定不对
发现 \(m\) 的范围比较小
也就是说有一些位置是不会被操作的,而且这样的位置很多
所以我们可以改变平衡树中维护的信息
将维护一个节点改为维护一个区间,可以理解为动态开点
节点上要多维护区间的左右端点以及长度
当对于某一个点进行操作时,就把当前节点所在的区间分成几个小区间扔进平衡树中
同时要开一个 \(map\) 记录一下每一个节点掌管的是哪一个区间
方便对于一个数快速查询它被哪一个节点所掌管
具体实现的过程中还是有很多细节的
代码
#include<cstdio>
#include<algorithm>
#include<map>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<ctime>
#define rg register
inline int read(){
rg int x=0,fh=1;
rg char ch=getchar();
while(ch<'0' || ch>'9'){
if(ch=='-') fh=-1;
ch=getchar();
}
while(ch>='0' && ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*fh;
}
const int maxn=1e6+5;
int cnt,rt,rt1,rt2,rt3,rt4,n,m;
std::map<int,int> mp;
#define mit std::map<int,int>::iterator
struct trr{
int ch[2],siz,rd,fa,l,r,len;
}tr[maxn];
void push_up(rg int da){
tr[da].siz=tr[tr[da].ch[0]].siz+tr[tr[da].ch[1]].siz+tr[da].len;
tr[tr[da].ch[0]].fa=da,tr[tr[da].ch[1]].fa=da;
}
int ad(rg int l,rg int r){
tr[++cnt].rd=rand();
mp[r]=cnt;
tr[cnt].l=l;
tr[cnt].r=r;
tr[cnt].len=r-l+1;
tr[cnt].siz=tr[cnt].len;
return cnt;
}
void split(rg int now,rg int val,rg int& x,rg int& y){
tr[now].fa=0;
if(!now){
x=y=0;
return;
}
if(tr[tr[now].ch[0]].siz+tr[now].len<=val){
x=now;
split(tr[now].ch[1],val-tr[tr[now].ch[0]].siz-tr[now].len,tr[now].ch[1],y);
} else {
y=now;
split(tr[now].ch[0],val,x,tr[now].ch[0]);
}
push_up(now);
}
int bing(rg int aa,rg int bb){
tr[aa].fa=0,tr[bb].fa=0;
if(!aa || !bb) return aa+bb;
if(tr[aa].rd<tr[bb].rd){
tr[aa].ch[1]=bing(tr[aa].ch[1],bb);
push_up(aa);
return aa;
} else {
tr[bb].ch[0]=bing(aa,tr[bb].ch[0]);
push_up(bb);
return bb;
}
}
int getrk(rg int da){
rg int nans=tr[tr[da].ch[0]].siz+tr[da].len;
while(tr[da].fa){
if(tr[tr[da].fa].ch[1]==da){
da=tr[da].fa;
nans+=tr[tr[da].ch[0]].siz+tr[da].len;
} else {
da=tr[da].fa;
}
}
return nans;
}
int kth(rg int da,rg int k){
while(1){
if(k>tr[tr[da].ch[0]].siz+tr[da].len){
k-=tr[tr[da].ch[0]].siz+tr[da].len;
da=tr[da].ch[1];
} else if(k<=tr[tr[da].ch[0]].siz+tr[da].len && k>=tr[tr[da].ch[0]].siz+1){
return da;
} else {
da=tr[da].ch[0];
}
}
}
int latans;
int main(){
srand(time(0));
n=read(),m=read();
rt=ad(1,n);
rg int aa,bb,cc,dd,ee;
rg mit it;
for(rg int i=1;i<=m;i++){
aa=read(),bb=read();
bb-=latans;
if(aa==1){
cc=read();
cc-=latans;
it=mp.lower_bound(bb);
dd=it->second;
ee=getrk(dd);
mp.erase(it);
split(rt,ee-1,rt,rt1);
split(rt1,tr[dd].len,rt1,rt2);
if(tr[dd].l!=bb) rt=bing(rt,ad(tr[dd].l,bb-1));
rt=bing(rt,ad(cc,cc));
if(tr[dd].r!=bb) rt=bing(rt,ad(bb+1,tr[dd].r));
rt=bing(rt,rt2);
printf("%d\n",latans=getrk(mp[cc]));
} else if(aa==2){
it=mp.lower_bound(bb);
dd=it->second;
ee=getrk(dd);
mp.erase(it);
printf("%d\n",latans=ee-(tr[dd].r-bb));
split(rt,ee-1,rt,rt1);
split(rt1,tr[dd].len,rt1,rt2);
rt=bing(ad(bb,bb),rt);
if(tr[dd].l!=bb) rt=bing(rt,ad(tr[dd].l,bb-1));
if(tr[dd].r!=bb) rt=bing(rt,ad(bb+1,tr[dd].r));
rt=bing(rt,rt2);
} else if(aa==3){
it=mp.lower_bound(bb);
dd=it->second;
ee=getrk(dd);
mp.erase(it);
printf("%d\n",latans=ee-(tr[dd].r-bb));
split(rt,ee-1,rt,rt1);
split(rt1,tr[dd].len,rt1,rt2);
if(tr[dd].l!=bb) rt=bing(rt,ad(tr[dd].l,bb-1));
if(tr[dd].r!=bb) rt=bing(rt,ad(bb+1,tr[dd].r));
rt=bing(rt,rt2);
rt=bing(rt,ad(bb,bb));
} else {
dd=kth(rt,bb);
ee=getrk(dd);
printf("%d\n",latans=tr[dd].r-(ee-bb));
}
}
return 0;
}
洛谷P3285 [SCOI2014]方伯伯的OJ 动态开点平衡树的更多相关文章
- 洛谷 P3285 [SCOI2014]方伯伯的OJ
看到这题,第一眼:平衡树水题,随便做一做好了 然后....我在花了n个小时去调试(维护平衡树父节点)之后,... 调了三个小时后,第一次失败的代码(只能查找排名为k的用户编号,不能根据编号查排名) # ...
- 洛谷 P3285 - [SCOI2014]方伯伯的OJ(平衡树)
洛谷题面传送门 在酒店写的,刚了一整晚终于调出来了-- 首先考虑当 \(n\) 比较小(\(10^5\) 级别)的时候怎么解决,我们考虑将所有用户按排名为关键字建立二叉排序树,我们同时再用一个 map ...
- 洛谷P3286 [SCOI2014]方伯伯的商场之旅
题目:洛谷P3286 [SCOI2014]方伯伯的商场之旅 思路 数位DP dalao说这是数位dp水题,果然是我太菜了... 自己是不可能想出来的.这道题在讲课时作为例题,大概听懂了思路,简单复述一 ...
- luogu P3285 [SCOI2014]方伯伯的OJ splay 线段树
LINK:方伯伯的OJ 一道稍有质量的线段树题目.不写LCT splay这辈子是不会单独写的 真的! 喜闻乐见的是 题目迷惑选手 \(op==1\) 查改用户在序列中的位置 题目压根没说位置啊 只有排 ...
- 洛谷 P3287 - [SCOI2014]方伯伯的玉米田(BIT 优化 DP)
洛谷题面传送门 怎么题解区全是 2log 的做法/jk,这里提供一种 1log 并且代码更短(bushi)的做法. 首先考虑对于一个序列 \(a\) 怎样计算将其变成单调不降的最小代价.对于这类涉及区 ...
- 洛谷P3287 [SCOI2014]方伯伯的玉米田(树状数组)
传送门 首先要发现,每一次选择拔高的区间都必须包含最右边的端点 为什么呢?因为如果拔高了一段区间,那么这段区间对于它的左边是更优的,对它的右边会更劣,所以我们每一次选的区间都得包含最右边的端点 我们枚 ...
- 洛谷3288 SCOI2014方伯伯运椰子(分数规划+spfa)
纪念博客又一次爆炸了 首先,对于本题中,我们可以发现,保证存在正整数解,就表示一定费用会降低.又因为一旦加大的流量,费用一定会变大,所以总流量一定是不变的 那么我们这时候就需要考虑一个退流的过程 对于 ...
- BZOJ 3595: [Scoi2014]方伯伯的Oj SBT+可持久化Treap
3595: [Scoi2014]方伯伯的Oj Time Limit: 6 Sec Memory Limit: 256 MBSubmit: 102 Solved: 54[Submit][Status ...
- 洛谷 P3285 / loj 2212 [SCOI2014] 方伯伯的 OJ 题解【平衡树】【线段树】
平衡树分裂钛好玩辣! 题目描述 方伯伯正在做他的 OJ.现在他在处理 OJ 上的用户排名问题. OJ 上注册了 \(n\) 个用户,编号为 \(1\sim n\),一开始他们按照编号排名.方伯伯会按照 ...
随机推荐
- nuoyanli 520 Let‘s play computer game
H题 描述 xxxxxxxxx在疫情期间迷上了一款游戏,这个游戏一共有nnn个地点(编号为1--n1--n1--n),他每次从一个地点移动到另外一个地点需要消耗 一定的能量,每一个地点都有一些珠宝,输 ...
- 5.PowerShell DSC核心概念之资源
什么是资源? 资源为 DSC 配置提供构建基块. 资源公开可配置的属性,并包含本地配置管理器 (LCM) 调用以"使其如此"的 PowerShell 脚本函数. 系统内置资源 可在 ...
- OpenStack Train版-11.安装horizon服务(计算节点)
OpenStack仪表板Dashboard服务的项目名称是Horizon,它所需的唯一服务是身份服务keystone,开发语言是python的web框架Django. 安装Train版本的Horizo ...
- Eazfuscator.NET(.net混淆工具)
软件功能 调试支持: 在你的程序集被Eazfuscator.NET混淆后,它不会成为不可调试混乱的砖块.你总是可以得到一个行号,出现未处理的异常,查看可读的堆栈跟踪,甚至附加调试器来遍历你的模糊代码. ...
- Java之浅拷贝和深拷贝
[概述] Java中的对象拷贝 ( Object Copy ) 是指将一个对象的所有属性(成员变量)拷贝到另一个有着相同类类型的对象中去.例如,对象 A 和对象 B 都属于类 S,具有属性 a 和 b ...
- Spring(四) SpringDI(1)
Spring 自动装配之依赖注入 依赖注入发生的时间 当 Spring IOC 容器完成了 Bean 定义资源的定位.载入和解析注册以后,IOC 容器中已经管理类 Bean 定义的相关数据,但是此时 ...
- Google Chrome 怎么在退出时自动删除历史记录
1 Google Chrome 怎么在退出时自动删除历史记录 https://chrome.google.com/webstore/detail/clickclean/ghgabhipcejejjmh ...
- 使用 js 实现一个简易版的模版引擎
使用 js 实现一个简易版的模版引擎 regex (function test() { this.str = str; })( window.Test = ...; format() { let ar ...
- cnblogs 日期错乱 bug
cnblogs 日期错乱 bug 时间错乱 bug archive/2004/01/13/ 什么鬼 呀默认时间戳 https://www.cnblogs.com/xgqfrms/archive/200 ...
- bash for mac
bash for mac https://sourabhbajaj.com/mac-setup/iTerm/ https://sourabhbajaj.com/mac-setup/iTerm/zsh. ...