洛谷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\),一开始他们按照编号排名.方伯伯会按照 ...
随机推荐
- Paths on a Grid POJ - 1942 排列组合
题意: 从左下角移动到右上角.每次只能向上或者向右移动一格.问移动的轨迹形成的右半边图形有多少种 题解: 注意,这个图形就根本不会重复,那就是n*m的图形,向上移动n次,向右移动m次. 从左下角移动到 ...
- Codeforces #620 div2 B
题目: Returning back to problem solving, Gildong is now studying about palindromes. He learned that a ...
- 13. 从0学ARM-Cortex-A9 RTC裸机程序编写
一.RTC RTC(Real-Time Clock) 实时时钟. RTC是集成电路,通常称为时钟芯片.在一个嵌入式系统中,通常采用RTC来提供可靠的系统时间,包括时分秒和年月日等,而且要求在系统处于关 ...
- 微信小程序swiper实现 句子控app首页滑动卡片
微信小程序swiper实现 句子控app首页滑动卡片 引言:最近看到句子控APP首页的效果很清新,可是发现他的微信小程序端没有实现这个功能,我看了一下难度不大,于是尝试着去实现. 实现效果如下: 1. ...
- k8s-0-集群
Docker回顾 docker容器封装应用程序好处 内核在3.8以上,才能完整使用docker隔离功能(所有centos6不推荐用) Docker容器化封装应用程序缺点 容器编排工具有哪些 一: K8 ...
- 实战交付一套dubbo微服务到k8s集群(8)之configmap使用
使用ConfigMap管理应用配置 拆分环境 主机名 角色 IP地址 mfyxw10.mfyxw.com zk1.od.com(Test环境) 192.168.80.10 mfyxw20.mfyxw. ...
- MySQL 误删用户故障解决方案
目录 "误删"所有用户 解决方式一: 停止数据库 跳过 授权表 和 网络启动(重要) 插入新的用户 重启启动数据库 解决方式二: 停止数据库 跳过 授权表 和 网络启动(重要) 授 ...
- pycharm 与 anaconda 关联
anaconda Anaconda指的是一个开源的Python发行版本,集成了许多数据分析的库. 使用tersorflow进行机器学习时常用Anaconda pycharm PyCharm是一种Pyt ...
- Redis-第八章节-应用场景
目录 概述 详解 1.概述 Redis支持五种数据类型:String(字符串).Hash(哈希).List(列表).Set(集合).Zset(有序集合). 2.详解 1.String(字符串) 定义: ...
- Virtualbox 安装centos7虚拟机
Virtualbox 安装centos7虚拟机 一,下载centos7 下载地址:https://mirrors.tuna.tsinghua.edu.cn/centos/7.9.2009/isos/x ...