洛谷题面传送门

在酒店写的,刚了一整晚终于调出来了……

首先考虑当 \(n\) 比较小(\(10^5\) 级别)的时候怎么解决,我们考虑将所有用户按排名为关键字建立二叉排序树,我们同时再用一个 map 维护下编号为 \(x\) 的用户在原平衡树上对应的节点编号是什么。那么对于每次操作我们需进行的操作如下:

  • \(1\) 类操作:直接在 map 中找到 \(x\) 对应的节点编号,将该节点对应的用户编号改为 \(y\),同时更新 map 中用户编号为 \(y\) 对应的节点编号。
  • \(2\) 类操作:在 map 中找到 \(x\) 对应的节点编号 \(id\),然后将 \(id\) 从原平衡树中分离出来,然后将 \(id\) 与根节点合并,其中 \(id\) 排名小于根节点的排名。那么怎么实现分离这一操作呢?相较于普通的平衡树不同的一点是,这次我们对于每个点记录其父亲编号,然后假设我们要将 \(p\) 节点分离出来,那么我们就考察其父亲,如果其没有父亲我们就直接将根节点设为 \(p\) 左右儿子合并的结果,如果 \(p\) 是其父亲的左儿子(类似于 splay 里的 identify 函数)就将其父亲的左儿子设为 \(p\) 左右儿子合并的结果,否则将其父亲的右儿子设为 \(p\) 左右儿子合并的结果。同时将 \(p\) 左右儿子即父亲都设为空。
  • \(3\) 类操作:与 \(2\) 类操作几乎一致,只不过这次我们将 \(id\) 合并到根节点后面。
  • \(4\) 类操作:直接在平衡树上二分,然后输出对应节点用户编号。

接下来考虑原问题。注意到不同编号虽然很多,但是如果我们把编号连续排名也连续的这些编号合并起来,那么每次操作最多增加两个合并后的连续段,也就是说这个连续段的个数是 \(\mathcal O(m)\) 的,因此我们考虑平衡树上每个节点维护一个编号的连续段。同样地我们也可以用某种数据结构找到每个点所在连续段对应的节点编号,只不过由于此题用户个数很多,使用 map 逐一存储不可取,因此我们考虑建一个 set 并将所有连续段左端点及其编号看作一个二元组压入一个 set,查询在 set 中二分即可。同时由于每次修改可能会增加新的连续段,因此我们要将一个节点裂成两个,具体来说假设我们要将 \([L,R]\) 从中间 \(p\) 处断开,那么我们就新建两个节点表示 \([L,p-1]\) 和 \([p+1,R]\),然后将 \([L,p-1]\) 放在该节点左边,\([p+1,R]\) 放在该节点右边,原节点编号区间改为 \([p,p]\) 即可。注意这里“将 \([L,p-1]\) 挂在该节点左边”不能直接简简单单地将 \([L,p-1]\) 设为原节点的左儿子,同时将原来该节点的左儿子挂在 \([L,p-1]\) 的左儿子处,而要将 \([L,p-1]\) 与该节点原来的左儿子做一遍 merge 操作,否则复杂度会退化。

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

const int MAXM=2e5;
int n,qu;
struct node{
int sum,val,key,st,ch[2],f;
node(int _sum=0,int _val=0,int _st=0){
sum=_sum;val=_val;st=_st;key=rand();
ch[0]=ch[1]=f=0;
}
} s[MAXM+5];
int rt=1,ncnt=1;set<pii> nds;
void pushup(int k){s[k].sum=s[s[k].ch[0]].sum+s[s[k].ch[1]].sum+s[k].val;}
void setson(int k,int c,int v){s[v].f=k;s[k].ch[c]=v;}
int get(int x){pii p=*--nds.upper_bound(mp(x,INF));return p.se;}
int merge(int x,int y){
if(!x||!y) return x+y;
if(s[x].key<s[y].key) return setson(x,1,merge(s[x].ch[1],y)),pushup(x),x;
else return setson(y,0,merge(x,s[y].ch[0])),pushup(y),y;
}
void split_nd(int k,int p){
// printf("split %d %d\n",k,p);
int L=s[k].st,R=s[k].st+s[k].val-1;
if(L==R) return;
nds.erase(nds.find(mp(L,k)));
if(p!=L){
int ls=++ncnt;s[ls]=node(p-L,p-L,L);
nds.insert(mp(L,ls));setson(k,0,merge(s[k].ch[0],ls));
} if(p!=R){
int rs=++ncnt;s[rs]=node(R-p,R-p,p+1);
nds.insert(mp(p+1,rs));setson(k,1,merge(rs,s[k].ch[1]));
} s[k].val=1;s[k].st=p;nds.insert(mp(p,k));
}
int query(int sz){
int k=rt;
while(1){
// printf("%d %d %d\n",k,sz,s[k].st);
if(sz<=s[s[k].ch[0]].sum) k=s[k].ch[0];
else if(sz>s[s[k].ch[0]].sum+s[k].val) sz-=s[s[k].ch[0]].sum+s[k].val,k=s[k].ch[1];
else return s[k].st+sz-s[s[k].ch[0]].sum-1;
}
}
void print(int k){
if(!k) return;print(s[k].ch[0]);
printf("node %d [%d,%d] %d %d %d %d\n",k,s[k].st,s[k].st+s[k].val-1,s[k].sum,s[k].f,s[k].ch[0],s[k].ch[1]);
print(s[k].ch[1]);
}
int walk(int k){
// printf("walk %d\n",k);print(rt);
int res=1+s[s[k].ch[0]].sum,pr=k;
while(k){
k=s[k].f;//printf("%d\n",k);
if(pr==s[k].ch[1]) res+=s[s[k].ch[0]].sum,res+=s[k].val;
pr=k;
} return res;
}
int main(){
scanf("%d%d",&n,&qu);srand(20211005203353);
s[1]=node(n,n,1);nds.insert(mp(1,1));int pre=0;
while(qu--){
int opt;scanf("%d",&opt);
if(opt==1){
int x,y;scanf("%d%d",&x,&y);
x-=pre;y-=pre;int pt=get(x);
split_nd(pt,x);s[pt].st=y;
nds.erase(nds.find(mp(x,pt)));
nds.insert(mp(y,pt));
printf("%d\n",pre=walk(pt));
} else if(opt==2){
int x;scanf("%d",&x);x-=pre;
int pt=get(x);split_nd(pt,x);
printf("%d\n",pre=walk(pt));
int nd=merge(s[pt].ch[0],s[pt].ch[1]);
s[pt].ch[0]=s[pt].ch[1]=0;pushup(pt);
if(s[pt].f){
int fa=s[pt].f;
if(s[fa].ch[0]==pt) setson(fa,0,nd);
else setson(fa,1,nd);
} else rt=nd,s[rt].f=0;
for(int j=s[pt].f;j;j=s[j].f) pushup(j);
s[pt].f=0;
rt=merge(pt,rt);
} else if(opt==3){
int x;scanf("%d",&x);x-=pre;
int pt=get(x);split_nd(pt,x);
printf("%d\n",pre=walk(pt));
int nd=merge(s[pt].ch[0],s[pt].ch[1]);
s[pt].ch[0]=s[pt].ch[1]=0;pushup(pt);
if(s[pt].f){
int fa=s[pt].f;
if(s[fa].ch[0]==pt) setson(fa,0,nd);
else setson(fa,1,nd);
} else rt=nd,s[rt].f=0;
for(int j=s[pt].f;j;j=s[j].f) pushup(j);
s[pt].f=0;
rt=merge(rt,pt);
} else {
int k;scanf("%d",&k);k-=pre;
printf("%d\n",pre=query(k));
}
}
return 0;
}

洛谷 P3285 - [SCOI2014]方伯伯的OJ(平衡树)的更多相关文章

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

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

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

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

  3. 洛谷P3286 [SCOI2014]方伯伯的商场之旅

    题目:洛谷P3286 [SCOI2014]方伯伯的商场之旅 思路 数位DP dalao说这是数位dp水题,果然是我太菜了... 自己是不可能想出来的.这道题在讲课时作为例题,大概听懂了思路,简单复述一 ...

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

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

  5. 洛谷 P3287 - [SCOI2014]方伯伯的玉米田(BIT 优化 DP)

    洛谷题面传送门 怎么题解区全是 2log 的做法/jk,这里提供一种 1log 并且代码更短(bushi)的做法. 首先考虑对于一个序列 \(a\) 怎样计算将其变成单调不降的最小代价.对于这类涉及区 ...

  6. 洛谷P3287 [SCOI2014]方伯伯的玉米田(树状数组)

    传送门 首先要发现,每一次选择拔高的区间都必须包含最右边的端点 为什么呢?因为如果拔高了一段区间,那么这段区间对于它的左边是更优的,对它的右边会更劣,所以我们每一次选的区间都得包含最右边的端点 我们枚 ...

  7. 洛谷3288 SCOI2014方伯伯运椰子(分数规划+spfa)

    纪念博客又一次爆炸了 首先,对于本题中,我们可以发现,保证存在正整数解,就表示一定费用会降低.又因为一旦加大的流量,费用一定会变大,所以总流量一定是不变的 那么我们这时候就需要考虑一个退流的过程 对于 ...

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

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

  9. 洛谷 P3285 / loj 2212 [SCOI2014] 方伯伯的 OJ 题解【平衡树】【线段树】

    平衡树分裂钛好玩辣! 题目描述 方伯伯正在做他的 OJ.现在他在处理 OJ 上的用户排名问题. OJ 上注册了 \(n\) 个用户,编号为 \(1\sim n\),一开始他们按照编号排名.方伯伯会按照 ...

随机推荐

  1. Promise.resolve(x)中x有几种情况

    ps:下面参数说的是Promise.resolve(x)中的x 一共四种情况: 1.如果参数是Promise实例本身,则抛出错误 2.如果参数是一个promise对象,则then函数的执行取决于这个参 ...

  2. 分库分表利器之Sharding Sphere(深度好文,看过的人都说好)

    Sharding-Sphere Sharding-JDBC 最早是当当网内部使用的一款分库分表框架,到2017年的时候才开始对外开源,这几年在大量社区贡献者的不断迭代下,功能也逐渐完善,现已更名为 S ...

  3. bash反弹shell

    part1:不求甚解的本地复现 攻击端Debian 10.x:  192.168.208.134 受害端Ubuntu : 192.168.208.135 攻击端打开(监听)某端口:  键入命令:[nc ...

  4. 【二食堂】Beta - Scrum Meeting 5

    Scrum Meeting 5 例会时间:5.18 18:30~18:50 进度情况 组员 当前进度 今日任务 李健 1. 划词功能已经实现,继续开发,完善文本区域交互,调用API issue 1. ...

  5. BUAA_2020_软件工程_结对项目作业

    项目 内容 这个作业属于哪个课程 班级博客 这个作业的要求在哪里 作业要求 我在这个课程的目标是 掌握软件工程的思路方法 这个作业在哪个具体方面帮助我实现目标 学习结对编程 教学班级 006 项目地址 ...

  6. 软工博客之关于CSDN的移动端软件测评

    关于CSDN的移动端软件测评 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任健) 这个作业的要求在哪里 软件测评作业 我在这个课程的目标 不求变强,只求做好,成为一颗有用的 ...

  7. 2021.8.18 NKOJ周赛总结

    两个字总结:安详 T1: NKOJ-6179 NP问题 问题描述: p6pou在平面上画了n个点,并提出了一个问题,称为N-Points问题,简称NP问题. p6pou首先在建立的平面直角坐标系,并标 ...

  8. 方阵里面的dp

    打了一场luogu的信心赛,惊讶地发现我不会T2,感觉像这样在矩阵里面的dp看起来很套路的样子,但是仔细想想还是有很多需要注意的细节. 又想到之前貌似也考过一些类似的题目 然而我并没有改 ,于是打算补 ...

  9. vue三级路由显示+面包屑

    问题一:如何让三级路由内容显示显示在一级路由页面 可以说是我点级二级路由导航的时候是不发生跳转的,但还要去动态的生成面包屑 const routes = [{ path: '/', name: 'Ho ...

  10. druid连接泄露故障分析

    1.问题的如何发生的 1.1.应用功能介绍 系统是一个双数据源双写单独的服务.(两个数据源是不同的存储,所以无法使用主从复制的模式,是一个切换存储介质的过渡态). 历史代码有个更新逻辑update x ...