由于n很大,有2e8,所以不能直接用splay来维护排名

把splay修改一下

每个节点维护一个区间[l,r],表示编号在[l,r]之间的所有点都在这里

需要支持一个takeout操作:

把编号为k的玩家分离出来,成为一个独立的点

先找到它所在的大点x

splay(x)

然后分裂成1-3个节点

关于如何查找编号为k的玩家在splay中哪个节点

可以开一棵动态开节点的线段树来维护

每次分裂实质就是区间赋值,打标记即可

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

写起来真是神清气爽…

#include<cstdio>
#define N 300010
#define M 9000000
const int R=200000000;
inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
int ans;
struct Segmenttree{
int tot,l[M],r[M],tag[M],val[M];
inline void make1(int x,int a,int b,int p){
if(!x)return;
if(a==b)val[x]=p;else tag[x]=p;
}
inline void pb(int x,int a,int b){
if(tag[x]){
int mid=(a+b)>>1;
if(!l[x])l[x]=++tot;
if(!r[x])r[x]=++tot;
make1(l[x],a,mid,tag[x]);
make1(r[x],mid+1,b,tag[x]);
tag[x]=0;
}
}
void change(int x,int a,int b,int c,int d,int p){
if(c<=a&&b<=d){
make1(x,a,b,p);
return;
}
int mid=(a+b)>>1;
pb(x,a,b);
if(c<=mid){
if(!l[x])l[x]=++tot;
change(l[x],a,mid,c,d,p);
}
if(d>mid){
if(!r[x])r[x]=++tot;
change(r[x],mid+1,b,c,d,p);
}
}
int ask(int x,int a,int b,int c){
if(a==b)return val[x];
int mid=(a+b)>>1;
pb(x,a,b);
return c<=mid?ask(l[x],a,mid,c):ask(r[x],mid+1,b,c);
}
inline void init(){
tot=1;
make1(1,1,R,1);
}
}S;
int tot,root,f[N],son[N][2],l[N],r[N],sum[N];
inline void init(int n){
tot=root=l[1]=1;r[1]=n;
}
inline void up(int x){sum[x]=sum[son[x][0]]+sum[son[x][1]]+r[x]-l[x]+1;}
inline void setson(int x,int w,int y){son[x][w]=y;if(y)f[y]=x;}
inline void rotate(int x){
int y=f[x],w=son[y][1]==x;
son[y][w]=son[x][!w];
if(son[x][!w])f[son[x][!w]]=y;
if(f[y]){
int z=f[y];
if(son[z][0]==y)son[z][0]=x;
if(son[z][1]==y)son[z][1]=x;
}
f[x]=f[y];f[y]=x;son[x][!w]=y;up(y);
}
inline void splay(int x){
while(f[x]){
int y=f[x];
if(f[y]){if((son[f[y]][0]==y)^(son[y][0]==x))rotate(x);else rotate(y);}
rotate(x);
}
up(root=x);
}
inline int kth(int k){
int x=root,nl,nr;
while(1){
nl=sum[son[x][0]]+1;nr=nl+r[x]-l[x];
if(nl<=k&&k<=nr)return k-nl+l[x];
if(k<nl)x=son[x][0];
else k-=nr,x=son[x][1];
}
}
inline int takeout(int k){//将编号为k的点分离成单点
int x=S.ask(1,1,R,k);
splay(x);
int tl=l[x],tr=r[x],sl=son[x][0],sr=son[x][1];
l[x]=r[x]=k;
if(k!=tl){
int y=++tot;
l[y]=tl;r[y]=k-1;
setson(y,0,sl);
up(y);
S.change(1,1,R,tl,k-1,y);
setson(x,0,y);
}else setson(x,0,sl);
if(k!=tr){
int y=++tot;
l[y]=k+1;r[y]=tr;
setson(y,1,sr);
up(y);
S.change(1,1,R,k+1,tr,y);
setson(x,1,y);
}else setson(x,1,sr);
up(x);
ans=sum[son[x][0]]+1;
return x;
}
inline void top(int k){//把编号为k的点放在首位
int x=takeout(k),a=son[x][0],b=son[x][1],i;
if(b){
f[b]=0;
i=b;
while(son[i][0])i=son[i][0];
splay(i);
setson(i,0,a);
up(i);
}else root=a;
son[x][0]=0;
setson(x,1,root);
up(root=x);
}
inline void bottom(int k){//把编号为k的点放在末尾
int x=takeout(k),a=son[x][0],b=son[x][1],i;
if(b){
f[b]=0;
i=b;
while(son[i][0])i=son[i][0];
splay(i);
setson(i,0,a);
up(i);
}else root=a;
son[x][1]=0;
setson(x,0,root);
up(root=x);
}
inline void change(int k,int p){//把编号为k的点的编号改为p
int x=takeout(k);
l[x]=r[x]=p;
S.change(1,1,R,p,p,x);
}
int n,m,k,x,y;
int main(){
read(n);read(m);
init(n);
S.init();
while(m--){
read(k);read(x);x-=ans;
if(k==1){
read(y);y-=ans;
change(x,y);
printf("%d\n",ans);
}
if(k==2)top(x),printf("%d\n",ans);
if(k==3)bottom(x),printf("%d\n",ans);
if(k==4)printf("%d\n",ans=kth(x));
}
return 0;
}

  

BZOJ3595 : [Scoi2014]方伯伯的Oj的更多相关文章

  1. [BZOJ3595][SCOI2014]方伯伯的OJ(裂点Splay)

    用一棵Splay按名次维护每个点,其中一个节点对应初始编号连续的一段区间,这样总节点数是$O(m)$的. 对每个编号记录这个点被Splay的那个节点维护,用std::map存储,只记录被修改的点. 每 ...

  2. 2019.03.28 bzoj3595: [Scoi2014]方伯伯的Oj(splay+map+set)

    传送门 题意简述: 给一个有优先级的nnn个人的序列,初始的时候第iii个人排名为iii,现在有mmm个操作,种类如下: 把编号为xxx的改成yyy,输出改前xxx的排名 把编号为xxx放到队首,输出 ...

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

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

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

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

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

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

  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. Linux内核之数据双链表

    导读 Linux 内核中自己实现了双向链表,可以在 include/linux/list.h 找到定义.我们将会首先从双向链表数据结构开始介绍内核里的数据结构.为什么?因为它在内核里使用的很广泛,你只 ...

  2. 删除右键ATI CATALYST(R) Control Center的方法

    http://share.weiyun.com/c47530d3e44ea15b606d4ba6f1b00a28

  3. php用soap创建webservice

    php提供了一个专门用于soap操作的扩展库,使用该扩展库后 可以直接在php中进行soap操作.下面将介绍soap的基本操作. 一.soap扩展的使用方法 php的soap扩展库通过soap协议实现 ...

  4. C 结构体小结

    看了三天结构体,是时候总结一下了. 关于结构体的声明: struct Student { ]; char sex; int age; ]; }; /*然后定义一个Student 类型的 student ...

  5. VMware Snapshot 工作原理

    VMware中的快照是对VMDK在某个时间点的“拷贝”,这个“拷贝”并不是对VMDK文件的复制,而是保持磁盘文件和系统内存在该时间点的状态,以便在出现故障后虚拟机能够恢复到该时间点.如果对某个虚拟机创 ...

  6. Unable to mount the CD/DVD image virtualbox解决方法

    转自: http://askubuntu.com/questions/321589/unable-to-mount-the-cd-dvd-image-on-the-machine-sandbox

  7. Selenium测试Ajax程序(转)

    上周末参加了Qclub的百度技术沙龙,听了百度的孙景卫讲了Web自动化测试,讲的非常好,然后在小组讨论时又有幸座在了一起.我们讨论的一个内容,就是Ajax应用程序比原来的非Ajax程序更不易测试,这里 ...

  8. iOS7 status bar 样式问题

    在ios7中,有如下status bar 样式 typedef NS_ENUM(NSInteger, UIStatusBarStyle) { UIStatusBarStyleDefault = , / ...

  9. Linux的文件管理

    绝对路径和相对路径: 绝对路径: /home/tony/Desktop 相对路径:Desktop 或者./Desktop不可写成/Desktop(这是绝对路径的写法) 其中.代表本层目录,..代表上层 ...

  10. AJAX,JSON用户名校验

    效果 开发结构 1,src部分有两个包dao和servlet 1.1dao包下有两个数据库工具类文件 SqlHelper.java package org.guangsoft.dao; import ...