平衡树分裂钛好玩辣!

题目描述

方伯伯正在做他的 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

现在你截获了方伯伯的所有操作,希望你能给出结果。

输入输出格式

输入格式:

输入的第一行包含两个用空格分隔的整数 \(n\) 和 \(m\),表示初始用户数和操作数。

此后有 \(m\) 行,每行是一个询问,询问格式如上所示。

输出格式:

输出包含 \(m\) 行。每行包含一个整数,其中第 \(i\) 行的整数表示第 \(i\) 个操作的输出。

输入输出样例

输入样例:

10 10
1 2 11
3 13
2 5
3 7
2 8
2 10
2 11
3 14
2 18
4 9

输出样例:

2
2
2
4
3
5
5
7
8
11

数据范围与说明

对于 \(100\%\) 的数据,\(1\le n\le 10^8,\ 1\le m\le 10^5\)。

输入保证对于所有的操作,\(x\) 必然已经出现在队列中,同时对于所有操作 1,\(1\le y\le 2\times 10^8\),并且 \(y\) 没有出现在队列中。

对于所有操作 4,保证 \(1\le k\le n\)。

题解:

平衡树”区间移动“题。

用带点分裂的 fhq Treap 移动区间,用线段树维护区间内元素在平衡树上的数组下标。

在平衡树上保留父亲信息。其中fa[root]=0 ,然后就可以顺着爬上去来计算每个节点的排名。

时间复杂度 \(O(m\log n)\)。

Code:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#define len(x) (r[x]-l[x]+1)
#define mid ((L+R)>>1)
#define N 200000000 namespace sgt
{
int ls[6000000],rs[6000000],v[6000000],lazy[6000000],pcnt=1;
void pushdown(int k,int L,int R)
{
if(!lazy[k]||L==R)
return;
int x=lazy[k];
v[ls[k]]=x;
lazy[ls[k]]=x;
v[rs[k]]=x;
lazy[rs[k]]=x;
lazy[k]=0;
return;
}
void change(int k,int l,int r,int L,int R,int x)//把区间[l,r]改成x
{
if(l<=L&&r>=R)
{
v[k]=x;
lazy[k]=x;
return;
}
if(r<L||l>R)
return;
if(!ls[k])
ls[k]=++pcnt;
if(!rs[k])
rs[k]=++pcnt;
pushdown(k,L,R);
change(ls[k],l,r,L,mid,x);
change(rs[k],l,r,mid+1,R,x);
}
int ask(int k,int p,int L,int R)//求点i的编号
{
if(!ls[k]&&!rs[k])
return v[k];
pushdown(k,L,R);
if(p<=mid)
return ask(ls[k],p,L,mid);
return ask(rs[k],p,mid+1,R);
}
}
int root=0; namespace bst
{
int rdm[200100],ls[200100],rs[200100],fa[200100];
int sz[200100],l[200100],r[200100];
int pcnt=0;
int Newnode(int L,int R)
{
++pcnt;
l[pcnt]=L;
r[pcnt]=R;
sz[pcnt]=R-L+1;
rdm[pcnt]=rand();
sgt::change(1,L,R,1,N,pcnt);
return pcnt;
}
void maintain(int k)
{
sz[k]=sz[ls[k]]+sz[rs[k]]+r[k]-l[k]+1;
fa[ls[k]]=k;
fa[rs[k]]=k;
}
int Merge(int a,int b)
{
if(!a||!b)
return a|b;
if(rdm[a]<rdm[b])
{
rs[a]=Merge(rs[a],b);
maintain(a);
return a;
}
ls[b]=Merge(a,ls[b]);
maintain(b);
return b;
}
void split(int rt,int x,int &a,int &b)
{
if(!rt)
{
a=0,b=0;
return;
}
int L=sz[ls[rt]],R=r[rt]-l[rt]+1;
if(x<=L)
{
b=rt;
split(ls[rt],x,a,ls[b]);
}
else if(x<L+R)
{
x-=L;
a=rt;
b=Newnode(l[rt]+x,r[rt]);
r[a]=l[rt]+x-1; rs[b]=rs[a];
rs[a]=0;
maintain(a);
maintain(b);
return;
}
else
{
a=rt;
split(rs[rt],x-L-R,rs[a],b);
}
maintain(rt);
}
int Rank(int p)
{
int k=sgt::ask(1,p,1,N); int ans=sz[ls[k]]+p-l[k]+1; while(fa[k])
{
if(k==rs[fa[k]])
ans+=sz[ls[fa[k]]]+len(fa[k]);
k=fa[k];
}
return ans;
}
} int main()
{
int n,m,op,x,y,z=0;
int a,b,c;
scanf("%d%d",&n,&m);
root=bst::Newnode(1,n);
while(m--)
{
scanf("%d",&op);
if(op==1)
{
scanf("%d%d",&x,&y);
x-=z,y-=z;
z=bst::Rank(x); printf("%d\n",z); bst::split(root,z-1,a,b);
bst::split(b,1,b,c); bst::l[b]=bst::r[b]=y;
sgt::change(1,y,y,1,N,b); root=bst::Merge(bst::Merge(a,b),c);
bst::fa[root]=0;
}
else if(op==2||op==3)
{
scanf("%d",&x);
x-=z;
z=bst::Rank(x); printf("%d\n",z); bst::split(root,z-1,a,b);
bst::split(b,1,b,c); if(op==2)
root=bst::Merge(bst::Merge(b,a),c);
else
root=bst::Merge(bst::Merge(a,c),b);
bst::fa[root]=0;
}
else
{
scanf("%d",&x);
x-=z;
bst::split(root,x-1,a,b);
bst::split(b,1,b,c);
z=bst::l[b];
printf("%d\n",z);
root=bst::Merge(bst::Merge(a,b),c);
bst::fa[root]=0;
}
}
return 0;
}

洛谷 P3285 / loj 2212 [SCOI2014] 方伯伯的 OJ 题解【平衡树】【线段树】的更多相关文章

  1. 洛谷 P3285 - [SCOI2014]方伯伯的OJ(平衡树)

    洛谷题面传送门 在酒店写的,刚了一整晚终于调出来了-- 首先考虑当 \(n\) 比较小(\(10^5\) 级别)的时候怎么解决,我们考虑将所有用户按排名为关键字建立二叉排序树,我们同时再用一个 map ...

  2. 洛谷P4458 /loj#2512.[BJOI2018]链上二次求和(线段树)

    题面 传送门(loj) 传送门(洛谷) 题解 我果然是人傻常数大的典型啊-- 题解在这儿 //minamoto #include<bits/stdc++.h> #define R regi ...

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

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

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

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

  5. 洛谷 P3919 【模板】可持久化数组(可持久化线段树/平衡树)-可持久化线段树(单点更新,单点查询)

    P3919 [模板]可持久化数组(可持久化线段树/平衡树) 题目背景 UPDATE : 最后一个点时间空间已经放大 标题即题意 有了可持久化数组,便可以实现很多衍生的可持久化功能(例如:可持久化并查集 ...

  6. 洛谷 P4125 [WC2012]记忆中的水杉树【扫描线+set+线段树】

    我没有找到能在bzojAC的代码--当然我也WA了--但是我在洛谷过了,那就假装过了吧 minmax线段树一开始写的只能用min更新min,max更新max,实际上是可以互相更新的-- 首先看第二问, ...

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

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

  8. 洛谷 P3285 [SCOI2014]方伯伯的OJ

    看到这题,第一眼:平衡树水题,随便做一做好了 然后....我在花了n个小时去调试(维护平衡树父节点)之后,... 调了三个小时后,第一次失败的代码(只能查找排名为k的用户编号,不能根据编号查排名) # ...

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

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

随机推荐

  1. 基于mosquitto的MQTT服务器---SSL/TLS 单向认证+双向认证

    基于mosquitto的MQTT服务器---SSL/TLS 单向认证+双向认证 摘自:https://blog.csdn.net/ty1121466568/article/details/811184 ...

  2. Servlet面试题

    Servlet运行在Servlet容器中,其生命周期由容器来管理.Servlet的生命周期通过javax.servlet.Servlet接口中的init().service()和destroy()方法 ...

  3. myeclipse如何将项目打包成war包

    打包步骤如下: 详细介绍请查看全文:https://cnblogs.com/qianzf/ 原文博客的链接地址:https://cnblogs.com/qzf/

  4. [GO]panic的应用

    对于异常的处理,error表示的是不太致使的错误,但是如果遇到数组越界或者是空指针这种会导致程序崩溃无法恢复的错误时,就需要使用以panic了 我们不应该使用panic去报error的错误,而是只使用 ...

  5. CentOS7 安装Maven3

    下载安装文件 cd /root wget http://mirrors.tuna.tsinghua.edu.cn/apache/maven/maven-3/3.3.9/binaries/apache- ...

  6. javascript总结46: JS三大系列-方便的offset 家族

    1 offset 家族 offset这个单词本身是--偏移,补偿,位移的意思. js中有一套方便的获取元素尺寸的办法就是offset家族: 2  offset 结构介绍为: 3 offset常用属性 ...

  7. C#和C++语言使用方面的区别

    本人觉得C#是世界上最优美的语言,也可以说是一门傻瓜语言,入门成本低,上手快得到许多人的青睐,但是C#并没有在行业内得到大家的首肯,反倒是C/C++人才比较紧俏:本人在学习过程中将C#和C++语言使用 ...

  8. MyEclipse中安装反编译插件

    如何查看MyEclipse中Spring等框架的源文件. 首先先下载一个插件:http://pan.baidu.com/share/link?shareid=644034672&uk=3508 ...

  9. Servlet 学习总结-1

    JavaWeb应用程序中所有的请求-响应都是由Servlet来完成的.Servlet是Java Web的核心程序,所有的网址(请求-响应)都交给Servlet来处理. Servlet在Web应用中被映 ...

  10. log4net 入门使用

    log4net 是dotnet平台下的一个日记记录组件. 一  NuGet中安装log4net包: 二 配置log4net.config文件 配置文件内容: <?xml version=&quo ...