洛谷 P3285 / loj 2212 [SCOI2014] 方伯伯的 OJ 题解【平衡树】【线段树】
平衡树分裂钛好玩辣!
题目描述
方伯伯正在做他的 OJ。现在他在处理 OJ 上的用户排名问题。
OJ 上注册了 \(n\) 个用户,编号为 \(1\sim n\),一开始他们按照编号排名。方伯伯会按照心情对这些用户做以下四种操作,修改用户的排名和编号:
- 操作格式为
1 x y,意味着将编号为 \(x\) 的用户编号改为 \(y\),而排名不变,执行完该操作后需要输出该用户在排名中的位置,数据保证 \(x\) 必然出现在排名中,同时 \(y\) 是一个当前不在排名中的编号。- 操作格式为
2 x,意味着将编号为 \(x\) 的用户的排名提升到第一位,执行完该操作后需要输出执行该操作前编号为 \(x\) 用户的排名。- 操作格式为
3 x,意味着将编号为 \(x\) 的用户的排名降到最后一位,执行完该操作后需要输出执行该操作前编号为 \(x\) 用户的排名。- 操作格式为
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 题解【平衡树】【线段树】的更多相关文章
- 洛谷 P3285 - [SCOI2014]方伯伯的OJ(平衡树)
洛谷题面传送门 在酒店写的,刚了一整晚终于调出来了-- 首先考虑当 \(n\) 比较小(\(10^5\) 级别)的时候怎么解决,我们考虑将所有用户按排名为关键字建立二叉排序树,我们同时再用一个 map ...
- 洛谷P4458 /loj#2512.[BJOI2018]链上二次求和(线段树)
题面 传送门(loj) 传送门(洛谷) 题解 我果然是人傻常数大的典型啊-- 题解在这儿 //minamoto #include<bits/stdc++.h> #define R regi ...
- 洛谷P3285 [SCOI2014]方伯伯的OJ 动态开点平衡树
洛谷P3285 [SCOI2014]方伯伯的OJ 动态开点平衡树 题目描述 方伯伯正在做他的 \(Oj\) .现在他在处理 \(Oj\) 上的用户排名问题. \(Oj\) 上注册了 \(n\) 个用户 ...
- BZOJ 3595: [Scoi2014]方伯伯的Oj SBT+可持久化Treap
3595: [Scoi2014]方伯伯的Oj Time Limit: 6 Sec Memory Limit: 256 MBSubmit: 102 Solved: 54[Submit][Status ...
- 洛谷 P3919 【模板】可持久化数组(可持久化线段树/平衡树)-可持久化线段树(单点更新,单点查询)
P3919 [模板]可持久化数组(可持久化线段树/平衡树) 题目背景 UPDATE : 最后一个点时间空间已经放大 标题即题意 有了可持久化数组,便可以实现很多衍生的可持久化功能(例如:可持久化并查集 ...
- 洛谷 P4125 [WC2012]记忆中的水杉树【扫描线+set+线段树】
我没有找到能在bzojAC的代码--当然我也WA了--但是我在洛谷过了,那就假装过了吧 minmax线段树一开始写的只能用min更新min,max更新max,实际上是可以互相更新的-- 首先看第二问, ...
- luogu P3285 [SCOI2014]方伯伯的OJ splay 线段树
LINK:方伯伯的OJ 一道稍有质量的线段树题目.不写LCT splay这辈子是不会单独写的 真的! 喜闻乐见的是 题目迷惑选手 \(op==1\) 查改用户在序列中的位置 题目压根没说位置啊 只有排 ...
- 洛谷 P3285 [SCOI2014]方伯伯的OJ
看到这题,第一眼:平衡树水题,随便做一做好了 然后....我在花了n个小时去调试(维护平衡树父节点)之后,... 调了三个小时后,第一次失败的代码(只能查找排名为k的用户编号,不能根据编号查排名) # ...
- [SCOI2014]方伯伯的OJ(线段树)
方伯伯正在做他的Oj.现在他在处理Oj上的用户排名问题.Oj上注册了n个用户,编号为1-n“,一开始他们按照编号排名. 方伯伯会按照心情对这些用户做以下四种操作,修改用户的排名和编号: 1.操作格式为 ...
随机推荐
- Spring Boot☞HelloWorld开篇
目录结构 POM.xml <?xml version="1.0" encoding="UTF-8"?> <project xmlns=&quo ...
- HUST软工1501-1503班第2周作业成绩公布
说明 本次公布的成绩对应的作业为: 第2周个人作业:WordCount编码和测试 如果同学对作业成绩存在异议,在成绩公布的72小时内(截止日期4月26日0点)可以进行申诉,方式如下: 毕博平台的第二周 ...
- scrapy爬虫事件以及数据保存为txt,json,mysql
今天要爬取的网页是虎嗅网 我们将完成如下几个步骤: 创建一个新的Scrapy工程 定义你所需要要抽取的Item对象 编写一个spider来爬取某个网站并提取出所有的Item对象 编写一个Item Pi ...
- HDU 6127 Hard challenge (极角扫描)
题意:给定 n 个点,和权值,他们两两相连,每条边的权值就是他们两个点权值的乘积,任意两点之间的直线不经过原点,让你从原点划一条直线,使得经过的直线的权值和最大. 析:直接进行极角扫描,从水平,然后旋 ...
- CodeForces 346A Alice and Bob (数学最大公约数)
题意:有一堆数,然后有两个人轮流从中取出两个数,这两个数的差的绝对值不在这个集合,然后把这个数放进这个集合,如果哪个人不能拿了,就是输了,问你谁赢. 析:当时连题意都没看好,以为拿出两个数,就不放回了 ...
- 编写高质量代码改善C#程序的157个建议——建议98:用params减少重复参数
建议98:用params减少重复参数 如果方法的参数数目不定,且参数类型一致,则可以使用params关键字减少重复参数声明. void Method1(string str, object a){} ...
- 我的CSS3学习笔记
1.元字符使用: []: 全部可选项 ||:并列 |:多选一 ?: 0个或者一个 *:0个或者多个 {}: 范围 2.CSS3属性选择器: E[attr]:存在attr属性即可: E[attr=val ...
- 【小梅哥FPGA进阶教程】MC8051软核在FPGA上的使用
十.MC8051软核在FPGA上的使用 本教程内容力求以详细的步骤和讲解让读者以最快的方式学会 MC8051 IP core 的应用以及相关设计软件的使用,并激起读者对 SOPC 技术的兴趣.本实验重 ...
- Linux系统root密码修改
重启系统. 进入系统引导界面: 按下e键: 选择第二项,内核启动参数设置,按下e键: 在结尾处,输入数字 1或者 英文 " single",再回车: 按下b键启动,此时以单用户模式 ...
- ARIA(Accessible Rich Internet Application)
ARIA 为Web app提供满足用户不同需求的解决方案.建设起用户和软件之间的桥梁. 新的HTML5标准中增加 aria-* 的标签属性,全称Accessible Rich Internet App ...