洛谷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\),一开始他们按照编号排名.方伯伯会按照 ...
随机推荐
- Drone构建失败,一次drone依赖下载超时导致构建失败的爬坑记录
Once upon a time, birds were singing in the forest, and people were dancing under the trees, It's so ...
- Spring:解决因@Async引起的循环依赖报错
最近项目中使用@Async注解在方法上引起了循环依赖报错: org.springframework.beans.factory.BeanCurrentlyInCreationException: Er ...
- np.random.randint()的返回值
返回的是数组而非int 比如返回x,y 为[1][2] 而非1,2 容易在只有一维一列时没有意识到 其他函数的返回值也要注意
- Python源码剖析——02虚拟机
<Python源码剖析>笔记 第七章:编译结果 1.大概过程 运行一个Python程序会经历以下几个步骤: 由解释器对源文件(.py)进行编译,得到字节码(.pyc文件) 然后由虚拟机按照 ...
- leetcode solution cracked tutorial
leetcode solution cracked tutorial problemset https://leetcode.com/problemset/all/ Top Interview Que ...
- css skeleton & web app skeleton
css skeleton & web app skeleton skeleton https://www.cnblogs.com/xgqfrms/p/10437258.html https:/ ...
- Nestjs 设置https
文档 只是用https import * as fs from 'fs'; import { NestFactory } from '@nestjs/core'; import { AppModule ...
- Flutter 使用p5
p5 工作示例 install dependencies: p5: ^0.0.5 main.dart import 'package:flutter/material.dart'; import &q ...
- 10月份上线的NGK有什么不同之处?
近日,有小道消息传出公链项目NGK即将在10月上线的消息.各大社区纷纷开始布局,市场中关于NGK项目的消息也变得更多了起来.仅是社区热度这一点,对比之下就已经优于很多项目,那么是否还有其他优势呢?让我 ...
- PAA房产,一家有温度的房产公司
PAUL ADAMS ARCHITECT房产(以下简称PAA,公司编号:07635831)对每一个客户从心出,为他们选择优质房源,为他们缔造家的温暖.PAA房产,是一家有温度的房产公司. PAA房产( ...