题意:

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的更多相关文章

  1. BZOJ 3595: [Scoi2014]方伯伯的Oj SBT+可持久化Treap

    3595: [Scoi2014]方伯伯的Oj Time Limit: 6 Sec  Memory Limit: 256 MBSubmit: 102  Solved: 54[Submit][Status ...

  2. 「SCOI2014」方伯伯的 OJ 解题报告

    「SCOI2014」方伯伯的 OJ 和列队有点像,平衡树点分裂维护即可 但是需要额外用个set之类的对编号查找点的位置 插入完了后记得splay,删除时注意特判好多东西 Code: #include ...

  3. 方伯伯的OJ ( onlinejudge )

    方伯伯的OJ 题目描述 方伯伯正在做他的OJ.现在他在处理OJ 上的用户排名问题. OJ 上注册了n 个用户,编号为1 ∼ n,一开始他们按照编号排名.方伯伯会按照心情对这些用户做以下四种操作,修改用 ...

  4. luogu P3285 [SCOI2014]方伯伯的OJ splay 线段树

    LINK:方伯伯的OJ 一道稍有质量的线段树题目.不写LCT splay这辈子是不会单独写的 真的! 喜闻乐见的是 题目迷惑选手 \(op==1\) 查改用户在序列中的位置 题目压根没说位置啊 只有排 ...

  5. 洛谷P3285 [SCOI2014]方伯伯的OJ 动态开点平衡树

    洛谷P3285 [SCOI2014]方伯伯的OJ 动态开点平衡树 题目描述 方伯伯正在做他的 \(Oj\) .现在他在处理 \(Oj\) 上的用户排名问题. \(Oj\) 上注册了 \(n\) 个用户 ...

  6. [SCOI2014]方伯伯的OJ(线段树)

    方伯伯正在做他的Oj.现在他在处理Oj上的用户排名问题.Oj上注册了n个用户,编号为1-n“,一开始他们按照编号排名. 方伯伯会按照心情对这些用户做以下四种操作,修改用户的排名和编号: 1.操作格式为 ...

  7. [SCOI2014]方伯伯的OJ

    看到这道题的第一想法就是要用FHQ treap 过了这道题...于是至今尚未成功(华丽的 T 掉了 (╯‵□′)╯︵┻━┻ ).于是附个地址. 然后水一波博客. 题意简介 emmmm...方伯伯脑抽做 ...

  8. 洛谷 P3285 / loj 2212 [SCOI2014] 方伯伯的 OJ 题解【平衡树】【线段树】

    平衡树分裂钛好玩辣! 题目描述 方伯伯正在做他的 OJ.现在他在处理 OJ 上的用户排名问题. OJ 上注册了 \(n\) 个用户,编号为 \(1\sim n\),一开始他们按照编号排名.方伯伯会按照 ...

  9. BZOJ 3595: [Scoi2014]方伯伯的Oj Splay + 动态裂点 + 卡常

    Description 方伯伯正在做他的Oj.现在他在处理Oj上的用户排名问题. Oj上注册了n个用户,编号为1-”,一开始他们按照编号排名.方伯伯会按照心情对这些用户做以下四种操作,修改用户的排名和 ...

随机推荐

  1. 微信-小程序-开发文档-服务端-模板消息:templateMessage.getTemplateLibraryList

    ylbtech-微信-小程序-开发文档-服务端-模板消息:templateMessage.getTemplateLibraryList 1.返回顶部 1. templateMessage.getTem ...

  2. 剑指offer——36二叉树和为某一值的路径

    题目描述 输入一颗二叉树的根节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径.路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径.(注意: 在返回值的list中,数组长度大 ...

  3. eclispe 创建maven 项目:Could not resolve archetype org.apache.maven.archetypes

    昨天新装eclispe 后,创建maven工程后出现 Could not resolve archetype org.apache.maven.archetypes:maven-archetype-q ...

  4. 【23. 合并K个排序链表】【困难】【优先队列/堆排序】

    合并 k 个排序链表,返回合并后的排序链表.请分析和描述算法的复杂度. 示例: 输入: [ 1->4->5, 1->3->4, 2->6] 输出: 1->1-> ...

  5. 【转】Java程序CPU飙升问题排查方法

    windows环境下cpu飙升问题 线上某台runtime机器(windows Server)cpu报警,这种情况初步就是代码里面死循环了,先把机器下线了保证不再有新的任务分配进来,然而cpu使用依然 ...

  6. jmeter在windows环境下系统参数设置

    在windows环境下搭建jmeter的压测实验环境,需要对操作系统默认的一些个参数进行设置,以提高并发能力.特别是作为压力机的时候. Socket 编程时,单机最多可以建立多少个 TCP 连接,受到 ...

  7. Aop 简单实例

    一 , 定义aop @Aspect @Component public class MyAspect { //* com 这里有个 空格 ! @Pointcut("execution(* c ...

  8. 数据库MySQL--连接查询

    例子文件1:https://files.cnblogs.com/files/Vera-y/myemployees.zip 例子文件2:https://files-cdn.cnblogs.com/fil ...

  9. 为什么串行传输时总是LSB在前?

    https://superuser.com/questions/1104212/why-do-serial-ports-send-data-least-significant-bit-first 其实 ...

  10. [JZOJ3348] 【NOI2013模拟】秘密任务

    题目 题目大意 给你一个无向图,你要割掉一些边使得\(1\)到\(n\)的所有最短路径被阻截. 割掉一个边\((u,v)\)的代价为\(a_u\)或\(a_v\)(记为两种不同的方案). 问最小代价及 ...