BZOJ3595 : [Scoi2014]方伯伯的Oj
由于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的更多相关文章
- [BZOJ3595][SCOI2014]方伯伯的OJ(裂点Splay)
用一棵Splay按名次维护每个点,其中一个节点对应初始编号连续的一段区间,这样总节点数是$O(m)$的. 对每个编号记录这个点被Splay的那个节点维护,用std::map存储,只记录被修改的点. 每 ...
- 2019.03.28 bzoj3595: [Scoi2014]方伯伯的Oj(splay+map+set)
传送门 题意简述: 给一个有优先级的nnn个人的序列,初始的时候第iii个人排名为iii,现在有mmm个操作,种类如下: 把编号为xxx的改成yyy,输出改前xxx的排名 把编号为xxx放到队首,输出 ...
- BZOJ 3595: [Scoi2014]方伯伯的Oj SBT+可持久化Treap
3595: [Scoi2014]方伯伯的Oj Time Limit: 6 Sec Memory Limit: 256 MBSubmit: 102 Solved: 54[Submit][Status ...
- 洛谷P3285 [SCOI2014]方伯伯的OJ 动态开点平衡树
洛谷P3285 [SCOI2014]方伯伯的OJ 动态开点平衡树 题目描述 方伯伯正在做他的 \(Oj\) .现在他在处理 \(Oj\) 上的用户排名问题. \(Oj\) 上注册了 \(n\) 个用户 ...
- luogu P3285 [SCOI2014]方伯伯的OJ splay 线段树
LINK:方伯伯的OJ 一道稍有质量的线段树题目.不写LCT splay这辈子是不会单独写的 真的! 喜闻乐见的是 题目迷惑选手 \(op==1\) 查改用户在序列中的位置 题目压根没说位置啊 只有排 ...
- [SCOI2014]方伯伯的OJ(线段树)
方伯伯正在做他的Oj.现在他在处理Oj上的用户排名问题.Oj上注册了n个用户,编号为1-n“,一开始他们按照编号排名. 方伯伯会按照心情对这些用户做以下四种操作,修改用户的排名和编号: 1.操作格式为 ...
- [SCOI2014]方伯伯的OJ
看到这道题的第一想法就是要用FHQ treap 过了这道题...于是至今尚未成功(华丽的 T 掉了 (╯‵□′)╯︵┻━┻ ).于是附个地址. 然后水一波博客. 题意简介 emmmm...方伯伯脑抽做 ...
- 洛谷 P3285 / loj 2212 [SCOI2014] 方伯伯的 OJ 题解【平衡树】【线段树】
平衡树分裂钛好玩辣! 题目描述 方伯伯正在做他的 OJ.现在他在处理 OJ 上的用户排名问题. OJ 上注册了 \(n\) 个用户,编号为 \(1\sim n\),一开始他们按照编号排名.方伯伯会按照 ...
- BZOJ 3595: [Scoi2014]方伯伯的Oj Splay + 动态裂点 + 卡常
Description 方伯伯正在做他的Oj.现在他在处理Oj上的用户排名问题. Oj上注册了n个用户,编号为1-”,一开始他们按照编号排名.方伯伯会按照心情对这些用户做以下四种操作,修改用户的排名和 ...
随机推荐
- mac os 安装 pkg-config
wget http://pkgconfig.freedesktop.org/releases/pkg-config-0.29.tar.gz . env LDFLAGS="-framework ...
- CUDA中的Toolkit
CUDA Toolkit是什么? 对于使用 C 语言和 C++ 来开发 GPU 加速应用程序的开发者来说,NVIDIA CUDA Toolkit 可提供一个综合的开发环境.CUDA Toolkit 包 ...
- gcc编译C++程序
gcc动态编译和静态编译方法 一.单个源.cpp文件生成可执行程序下面是一个保存在文件 helloworld.cpp 中一个简单的 C++ 程序的代码: /* helloworld.cpp */ #i ...
- nyoj19 全排列
http://acm.nyist.net/JudgeOnline/status.php?pid=19 #include<stdio.h> #include<stdlib.h> ...
- HDOJ 1203 I NEED A OFFER!(01背包)
10397507 2014-03-25 23:30:21 Accepted 1203 0MS 480K 428 B C++ 泽泽 题目链接:http://acm.hdu.edu.cn/showprob ...
- Python列表的remove方法的注意事项
为何没有删除列表中的全部元素? 解释: 按照执行顺序,第一个空格被删除之后,后面的元素会前移(变成['空格','空格','12','23']),指针下一次会指向新列表的第二个元素(即初始状态的第三个空 ...
- NSUrlConnection 和 NSUrlRequest 的关系
开始看到这2个名字,总感觉NSUrlConnection才是主要的网络请求类,其实不是,先看官方文档 An NSURLConnection object lets you load the conte ...
- Cocos2d-x 学习资料推荐
最近在看Cocos2d-x ,官网的资料太少了,下面推荐一些比较好的教程,不断更新中. 1. cocos2d-x高级开发教程 如果你懂得objective-c 那么一定要看看这本书,这里面有许多C++ ...
- C# 支持多种语言
通过Resource文件建立本地化. net 资源文件名(这里是Resource1.resx)由根名称(即Resource1),本地语言名称(默认情况下还没有)及扩展名组成,在读取资源时,资源管理器会 ...
- 4.python函数基础
一.函数 1.函数简介 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 函数能提高应用的模块性,和代码的重复利用率.你已经知道Python提供了许多内建函数,比如print().但 ...