loj2212 方伯伯的OJ
题意:

n<=1e8,m<=1e5.
标程:
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
using namespace std;
int read()
{
int x=,f=;char ch=getchar();
while (ch<''||ch>'') {if (ch=='-') f=-;ch=getchar();}
while (ch>=''&&ch<='') x=(x<<)+(x<<)+ch-'',ch=getchar();
return x*f;
}
const int N=;
map<int,int> mp;
int sz[N],son[N][],fa[N],L[N],R[N],tot,id[N],n,rt,m,mn,mx,ans,t,rk,x,y,op,g;
void up(int x) {sz[x]=sz[son[x][]]+sz[son[x][]]+R[x]-L[x]+;}
void rot(int &k,int x)
{
int y=fa[x],z=fa[y],l=(son[y][]==x),r=l^;
if (y==k) k=x;else son[z][(son[z][]==y)]=x;
fa[x]=z;fa[y]=x;fa[son[x][r]]=y;
son[y][l]=son[x][r];son[x][r]=y;
up(y);up(x);
}
void spl(int &k,int x)
{
for (int y;x!=k;rot(k,x))
if ((y=fa[x])!=k)
if (son[y][]==x^son[fa[y]][]==y) rot(k,x);else rot(k,y);
}
void ins(int &x,int l,int r,int idx,int f)//在splay的合适位置插入新区间
{
if (!x)
{
L[x=++tot]=l;R[tot]=r;id[tot]=idx;
sz[tot]=r-l+;fa[tot]=f;
return;
}
if (r<L[x]) ins(son[x][],l,r,idx,x);
else ins(son[x][],l,r,idx,x);
up(x);
}
void split(int x,int rk)
{
if (!son[x][]) rt=son[x][],fa[rt]=;//注意换根,保证splay连通
else {
int y=son[x][];
while (son[y][]) y=son[y][];
int z=son[x][];//注意转到根的下一个儿子处,不能转到根
spl(z,y); rt=y;fa[rt]=;
if (son[x][]) son[rt][]=son[x][];fa[son[x][]]=rt;
up(rt);
}
if (L[x]<=rk-) {ins(rt,L[x],rk-,L[x],);spl(rt,tot);}//注意spl前也要判断
if (rk+<=R[x]) {ins(rt,rk+,R[x],rk+,);spl(rt,tot);}
}
int find_rk(int x,int k)//查询rank为k的点(注意rank为k是离散的,不表示排在第k位)
{
if (L[x]<=k&&k<=R[x]) return x;
if (k<L[x]) return find_rk(son[x][],k);
else return find_rk(son[x][],k);
}
int qry_id(int x,int k)//查询rank_k的编号
{
if (k>sz[son[x][]]&&k<=sz[x]-sz[son[x][]])
{
if (L[x]==R[x]) return id[x];
else return L[x]+(k-sz[son[x][]])-;
}
if (k<=sz[son[x][]]) return qry_id(son[x][],k);
else return qry_id(son[x][],k-(sz[x]-sz[son[x][]]));
}
int main()
{
n=read();m=read();
mn=;mx=n;ins(rt,,n,,);//mn从-1往下开始标号,以0来区分是否标记。
while (m--)
{
op=read();x=read()-ans;
if (op==) {printf("%d\n",ans=qry_id(rt,x));continue;}
rk=mp[x];if (!rk) rk=x;
g=find_rk(rt,rk); spl(rt,g);
printf("%d\n",t=sz[son[g][]]+(rk-L[g]+));//离散排名转实际排名
split(g,rk);
if (op==)
{
y=read()-ans;
ins(rt,rk,rk,y,);spl(rt,tot);
mp[y]=rk;mp[x]=;
}else
{
mp[x]=(op==)?--mn:++mx;
ins(rt,mp[x],mp[x],x,);spl(rt,tot);
}
ans=t;
}
return ;
}
易错点:果然又调了很久,不过感觉自己数据分析能力又提高了。。。
1.spl删点换根的时候注意把y旋转到x的右儿子处。如果把y旋转到x处,那么y的右儿子不一定是x,有可能是z,而z的左儿子是x。
2.注意删点函数split中ins之后的splay也要判断是否在区间限制内,反之有可能tot恰好是被删掉的那一个而产生死循环。
3.mn从-1往下开始标号,以0来区分是否标记。
题解:splay+离散排名+区间分裂
一道splay好题。
一开始在纠结怎么实现排名和编号的双转换?
用mp保存每个点的离散排名(就是给不连续参数代替排名)。splay按照实际排名构造,用sz可以查询区间rank_k。对于splay上的每个点保存一段离散排名区间L~R。
排名转编号:排名->sz查询rank_k的点。
编号转排名:编号->离散排名rk->查找该离散排名所在的splay点g->sz[son[g][0]]+rk-L[g]+1.
一般splay是无法保存下所有节点的。
对于动态修改操作,参考noipDay2T3的做法。
一开始只有一个节点。一个节点中保存编号连续的点L~R。如果L!=R,那么这一段的点都没有修改过。执行一个修改操作,就把原来的一个区间删除修改点断开成两个,再插入修改后的点。
对于2和3操作,如果往前面加入的点,离散排名设为--mn,往后加则是++mx。为了节省map空间,只对修改排名的点记录。
这样时空复杂度就只跟操作有关。
也可以建三棵树,往前面加就扔进1树,不变就在2树,往后面加就扔进3树。这样2树中元素太多,可以记录不在2树中的元素(取补)。好像也可以权值线段树。
loj2212 方伯伯的OJ的更多相关文章
- BZOJ 3595: [Scoi2014]方伯伯的Oj SBT+可持久化Treap
3595: [Scoi2014]方伯伯的Oj Time Limit: 6 Sec Memory Limit: 256 MBSubmit: 102 Solved: 54[Submit][Status ...
- 「SCOI2014」方伯伯的 OJ 解题报告
「SCOI2014」方伯伯的 OJ 和列队有点像,平衡树点分裂维护即可 但是需要额外用个set之类的对编号查找点的位置 插入完了后记得splay,删除时注意特判好多东西 Code: #include ...
- 方伯伯的OJ ( onlinejudge )
方伯伯的OJ 题目描述 方伯伯正在做他的OJ.现在他在处理OJ 上的用户排名问题. OJ 上注册了n 个用户,编号为1 ∼ n,一开始他们按照编号排名.方伯伯会按照心情对这些用户做以下四种操作,修改用 ...
- luogu P3285 [SCOI2014]方伯伯的OJ splay 线段树
LINK:方伯伯的OJ 一道稍有质量的线段树题目.不写LCT splay这辈子是不会单独写的 真的! 喜闻乐见的是 题目迷惑选手 \(op==1\) 查改用户在序列中的位置 题目压根没说位置啊 只有排 ...
- 洛谷P3285 [SCOI2014]方伯伯的OJ 动态开点平衡树
洛谷P3285 [SCOI2014]方伯伯的OJ 动态开点平衡树 题目描述 方伯伯正在做他的 \(Oj\) .现在他在处理 \(Oj\) 上的用户排名问题. \(Oj\) 上注册了 \(n\) 个用户 ...
- [SCOI2014]方伯伯的OJ(线段树)
方伯伯正在做他的Oj.现在他在处理Oj上的用户排名问题.Oj上注册了n个用户,编号为1-n“,一开始他们按照编号排名. 方伯伯会按照心情对这些用户做以下四种操作,修改用户的排名和编号: 1.操作格式为 ...
- [SCOI2014]方伯伯的OJ
看到这道题的第一想法就是要用FHQ treap 过了这道题...于是至今尚未成功(华丽的 T 掉了 (╯‵□′)╯︵┻━┻ ).于是附个地址. 然后水一波博客. 题意简介 emmmm...方伯伯脑抽做 ...
- 洛谷 P3285 / loj 2212 [SCOI2014] 方伯伯的 OJ 题解【平衡树】【线段树】
平衡树分裂钛好玩辣! 题目描述 方伯伯正在做他的 OJ.现在他在处理 OJ 上的用户排名问题. OJ 上注册了 \(n\) 个用户,编号为 \(1\sim n\),一开始他们按照编号排名.方伯伯会按照 ...
- BZOJ 3595: [Scoi2014]方伯伯的Oj Splay + 动态裂点 + 卡常
Description 方伯伯正在做他的Oj.现在他在处理Oj上的用户排名问题. Oj上注册了n个用户,编号为1-”,一开始他们按照编号排名.方伯伯会按照心情对这些用户做以下四种操作,修改用户的排名和 ...
随机推荐
- Go中的switch fallthrough
Go基础 switch sExpr { case expr1: some instructions case expr2: some other instructions case expr3: ...
- Nt函数原型
NTSTATUS NTAPI NtAcceptConnectPort( OUT PHANDLE PortHandle, IN PVOID PortIdentifier, IN PPORT_MESSAG ...
- Linux下使用Eclipse 远程调试
1 开启端口 修改/apache-tomcat-7.0.40/bin/catalina.sh 在合适的位置(请自行判断,只要有JAVA_OPTS的设定前后即可)插入下面的设定:UI_DEBUG=&qu ...
- 【JUC】JDK1.8源码分析之ConcurrentHashMap
一.前言 最近几天忙着做点别的东西,今天终于有时间分析源码了,看源码感觉很爽,并且发现ConcurrentHashMap在JDK1.8版本与之前的版本在并发控制上存在很大的差别,很有必要进行认真的分析 ...
- Springboot-WebSocket获取HttpSession问题
换了新工作,第一个任务就是和这个有关,以前没接触过,没办法,各种度娘.谷哥,大部分都是只言片语,要么就是特定的配置环境还不贴配置--,踩坑无数, 遂整理成笔记 WebSocket协议 WebSocke ...
- express 创建项目
express 创建项目: 1.熟悉express命令 2.创建模板 3.安装组件
- PostgreSQL 主键自动增长
建立主键并设置自动增加的办法好好几种,这里记录我测试过的: drop table pro_process; CREATE TABLE "public"."pro_proc ...
- pandas中series求交集
在进行数据探索的时候会遇到求交集的情况,比如说:优惠卷预测的时候,有多张表,表1有用户id,表2也有用户id,但是不能确定表1的用户有多少出现在表2当中. un_id1,un_id2 为两个 Seri ...
- Random类和Math.random()方法
一.Random类的定义Random类位于 java.util 包中,主要用于生成伪 随机数Random类将 种子数 作为随机算法的起源数字,计算生成伪随机数,其与生成的随机数字的区间无关创建Rand ...
- lds 文件说明
主要符号说明 OUTPUT_FORMAT(bfdname) 指定输出可执行文件格式. OUTPUT_ARCH(bfdname) 指定输出可执行文件所运行 CPU 平台 ENTRY(symbol) 指定 ...