由于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. Window_搭建SVN服务器

    http://wenku.baidu.com/link?url=614FLi_VlhiJpyG5bq8JcwFBHroMjsV3FvBDzyyn0snZ85jbWx7xh-RPJdH7stxlgM9i ...

  2. Python os.system 和 os.popen的区别

    (1) os.system # 仅仅在一个子终端运行系统命令,而不能获取命令执行后的返回信息 system(command) -> exit_statusExecute the command ...

  3. OpenStack 的Nova组件详解

    Open Stack Compute Infrastructure (Nova) Nova是OpenStack云中的计算组织控制器.支持OpenStack云中实例(instances)生命周期的所有活 ...

  4. PHP中通过加号合并数组

    通常,我们合并多个数组用的是array_merge()函数,其实,PHP手册中关于数组操作符的介绍给了我们更简单的方法,那就是"+"号,看看下面的例子就明白了(详细了解) 代码: ...

  5. swift init继承问题

    当在子类的 designated init方法中不手动调用 父类的 designated init方法时,如果父类有不接受任何参数的init,那么系统会自动调用它,编译器不会报错.但是如果父类中没有不 ...

  6. apache AllowEncodedSlashes 允许URL中对路径分隔符进行编码

    2013年11月29日 10:35:32 情景: 你想通过在当前的URL中记录来源页面的URL,以便处理完请求后再跳转回来源页: http://www.example1.com/refer/http: ...

  7. putty mtputty 设置utf8编码

    2013年10月30日 10:02:36 先load你指定的ip 然后选择左侧目录中的windows->translation 再在右侧选择utf-8编码 选中后,点击左侧目录中的session ...

  8. delphi提示“Undeclared_identifier”的缺少引用单元列表

    _Stream ADODB_TLB akTop, akLeft, akRight, akBottom Controls Application (the variable not a type) Fo ...

  9. CPinyin unicode汉字查找拼音(支持多音字)

    下载代码 --------------------------------------------------------------------------------- 虽然很笨的办法,却非常有效 ...

  10. 解决 internet connection sharing 启动不了

    1.确认Windows Firewall服务是否启动(有异常可参考下面) a.打开注册表,找到HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ ...