P3369 【模板】普通平衡树 题解(Splay/FHQ)
题目链接
解题思路1:Splay
注意查询的时候大于小于等于号千万不要搞错了;注意适时伸展
AC代码1
#include<stdio.h>
#define root t[0].s[1]
struct Tree{
int s[2];//son
int sum;//总 数字 数
int cnt;//frequence
int f;//father
int data;
}t[200010];
int size,tot;//最大节点序号,总 数字 数
void upd(int x){
t[x].sum=t[t[x].s[0]].sum+t[t[x].s[1]].sum+t[x].cnt;//更新节点
}
int id(int x){//查询该节点为左儿子还是右儿子
return x==t[t[x].f].s[0]?0:1;
}
void connect(int x,int fa,int son){//x->fa,fa.son->x
t[x].f=fa;
t[fa].s[son]=x;
}
void rotate(int x){//x为中心的旋转
int y=t[x].f,idx=id(x),idy=id(y),B=t[x].s[idx^1],R=t[y].f;
connect(B,y,idx);
connect(y,x,idx^1);
connect(x,R,idy);
upd(y);upd(x);
}
void splay(int now,int to){//把now转为to的父亲的孩子节点(转到to的位置)
to=t[to].f;
while(to!=t[now].f){
int up=t[now].f;
if(to==t[up].f)rotate(now);//只能翻上去一次
else if(id(now)==id(up)){
rotate(up);
rotate(now);
}
else{
rotate(now);
rotate(now);
}
}
}
int create(int v,int fa){//建立节点
t[++size].data=v;
t[size].f=fa;
t[size].cnt=t[size].sum=1;
return size;
}
void push(int v){//找到插入的位置插入
int sign=0,nxt;
tot++;
if(!root)root=create(v,0);
else{
int now=root;
while(now){
t[now].sum++;
if(t[now].data==v){
t[now].cnt++,sign=now;
break;
}
nxt=t[now].data<v?1:0;
if(!t[now].s[nxt]){
sign=t[now].s[nxt]=create(v,now);
break;
}
now=t[now].s[nxt];
}
}
splay(sign,root);
}
int find(int v){
int now=root,nxt;
while(now){
if(t[now].data==v){
splay(now,root);
return now;
}
nxt=t[now].data<v?1:0;
now=t[now].s[nxt];
}
return 0;
}
void destroy(int x){//删除节点
t[x].cnt=t[x].data=t[x].f=t[x].sum=t[x].s[0]=t[x].s[1]=0;
if(x==size)size--;
}
void pop(int v){
int node=find(v);
if(!node)return;
tot--;
if(t[node].cnt>1){
t[node].cnt--,t[node].sum--;
return;
}
if(!t[node].s[0])root=t[node].s[1],t[root].f=0;
else{
int mx=t[node].s[0],B=t[node].s[1];
while(t[mx].s[1])mx=t[mx].s[1];//找到左子树最大点,翻上来
splay(mx,root);
connect(B,mx,1);
connect(mx,0,1);
upd(mx);
}
destroy(node);
}
int rank(int v){
int ans=0,now=root,nxt;
while(now){
if(t[now].data==v){
int r=ans+t[t[now].s[0]].sum+1;
splay(now,root);
return r;
}
nxt=t[now].data<v?1:0;
if(nxt)ans+=t[t[now].s[0]].sum+t[now].cnt;
now=t[now].s[nxt];
}
return ans;
}
int value(int x){
int now=root,les,res;
while(1){
les=t[t[now].s[0]].sum;
res=les+t[now].cnt;
if(res<x)now=t[now].s[1],x-=res;
else if(les>=x)now=t[now].s[0];
else{splay(now,root);return t[now].data;}
}
}
int upper(int v){
int now=root,res=1e9;
while(now){
if(t[now].data>v&&t[now].data<res)res=t[now].data;
now=t[now].s[t[now].data>v?0:1];
}
return res;
}
int lower(int v){
int now=root,res=-1e9;
while(now){
if(t[now].data<v&&t[now].data>res)res=t[now].data;
now=t[now].s[t[now].data>=v?0:1];//注意大于等于
}
return res;
}
int main(){
int i,n,opt,num;
scanf("%d",&n);
for(i=0;i<n;i++){
scanf("%d%d",&opt,&num);
if(opt==1)push(num);
else if(opt==2)pop(num);
else if(opt==3)printf("%d\n",rank(num));
else if(opt==4)printf("%d\n",value(num));
else if(opt==5)printf("%d\n",lower(num));
else printf("%d\n",upper(num));
}
return 0;
}
解题思路2:FHQ
AC代码2
#include<cstdio>
#include<cstdlib>
#define root t[0].s[1]
#define ls t[x].s[0]
#define rs t[x].s[1]
struct fhp{
int size,key,val,s[2];
}t[100010<<1];
int tot;
void upd(int x){
t[x].size=t[ls].size+t[rs].size+1;
}
void split(int x,int k,int &a,int &b){
if(!x){a=b=0;return;}
if(t[x].val<=k)a=x,split(rs,k,rs,b);
else b=x,split(ls,k,a,ls);
upd(x);
}
int merge(int x,int y){
if(!x||!y)return x+y;
if(t[x].key<t[y].key){rs=merge(rs,y),upd(x);return x;}
else{t[y].s[0]=merge(x,t[y].s[0]),upd(y);return y;}
}
int newnode(int v){
t[++tot].key=rand();
t[tot].val=v;
t[tot].size=1;
return tot;
}
void ins(int v){
int x,y;
split(root,v,x,y);
root=merge(merge(x,newnode(v)),y);
}
void del(int v){
int x,y,z;
split(root,v,x,y);
split(x,v-1,x,z);
z=merge(t[z].s[0],t[z].s[1]);
root=merge(x,merge(z,y));
}
void rank(int x){
int a,b;
split(root,x-1,a,b);
printf("%d\n",t[a].size+1);
root=merge(a,b);
}
void val(int x,int v){
while(1){
if(v<=t[ls].size)x=ls;
else if(v==t[ls].size+1){
printf("%d\n",t[x].val);
return;
}
else v-=t[ls].size+1,x=rs;
}
}
void pre(int v){
int x,y;
split(root,v-1,x,y);
val(x,t[x].size);
root=merge(x,y);
}
void suc(int v){
int x,y;
split(root,v,x,y);
val(y,1);
root=merge(x,y);
}
int main(){
int n,opt,num;
scanf("%d",&n);
while(n--){
scanf("%d%d",&opt,&num);
if(opt==1)ins(num);
else if(opt==2)del(num);
else if(opt==3)rank(num);
else if(opt==4)val(root,num);
else if(opt==5)pre(num);
else suc(num);
}
return 0;
}
P3369 【模板】普通平衡树 题解(Splay/FHQ)的更多相关文章
- 【洛谷P3369】【模板】普通平衡树题解
[洛谷P3369][模板]普通平衡树题解 题目链接 题意: 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:1. 插入x数2. 删除x数(若有多个相同的数,因只删除一个)3 ...
- luoguP3391[模板]文艺平衡树(Splay) 题解
链接一下题目:luoguP3391[模板]文艺平衡树(Splay) 平衡树解析 这里的Splay维护的显然不再是权值排序 现在按照的是序列中的编号排序(不过在这道题目里面就是权值诶...) 那么,继续 ...
- fhq_treap || BZOJ 3223: Tyvj 1729 文艺平衡树 || Luogu P3391 【模板】文艺平衡树(Splay)
题面: [模板]文艺平衡树(Splay) 题解:无 代码: #include<cstdio> #include<cstring> #include<iostream> ...
- P3391 【模板】文艺平衡树(Splay)新板子
P3391 [模板]文艺平衡树(Splay) 题目背景 这是一道经典的Splay模板题——文艺平衡树. 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转 ...
- luoguP3369[模板]普通平衡树(Treap/SBT) 题解
链接一下题目:luoguP3369[模板]普通平衡树(Treap/SBT) 平衡树解析 #include<iostream> #include<cstdlib> #includ ...
- P3369 【模板】普通平衡树(splay)
P3369 [模板]普通平衡树 就是不用treap splay板子,好好背吧TAT #include<iostream> #include<cstdio> #include&l ...
- 洛谷——P3369 【模板】普通平衡树(splay)(基础splay,维护一些神奇的东东)
P3369 [模板]普通平衡树 平衡树大法好,蒟蒻(博主)最近正在收集高级数据结构的碎片,企图合成数据结构的元素之力来使自己的RP++... 您需要写一种数据结构(可参考题目标题),来维护一些数,其中 ...
- 洛谷P3391 【模板】文艺平衡树(Splay)(FHQ Treap)
题目背景 这是一道经典的Splay模板题——文艺平衡树. 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1, ...
- 洛谷P3369 【模板】普通平衡树(Splay)
题面 传送门 题解 鉴于最近的码力实在是弱到了一个境界--回来重新打一下Splay的板子--竟然整整调了一个上午-- //minamoto #include<bits/stdc++.h> ...
随机推荐
- Chapter Zero 0.2.2 内存
目录 内存 内存的多通道设计 DRAM 和 SRAM 只读存储器(ROM) RAM.ROM以及硬盘的区别(转自百度) 内存 CPU的数据都是来自主存储器(main memory),个人计算机的主寄存器 ...
- ArcGIS Mobile 自定义图层在绘制面时节点未绘制完全的问题
ArcGIS Mobile 自定义图层在绘制面时节点未绘制完全,如下图: 面的绘制代码如下: public void Draw(Display dis, Pen p1, Pen p2,Pen p3 , ...
- Hexo准备---Node.js、Vue
Hexo准备---Node.js.Vue 安装node.js 1.下载node 配置node.js环境官网下载,一直next就好,非常方便. 下载官网: http://nodejs.cn/downlo ...
- 计算机网络基础篇-ppp协议
所谓的PPP协议是点对点协议,是目前使用最广泛的数据链路层的协议.大部分用户使用电话线拨号入网的,从用户计算机到ISP的链路所使用的数据链路层协议就是PPP协议. 首先介绍下拨号入网的过程.因特网服务 ...
- 蓝桥杯——试题 算法训练 Sereja and Squares
Java 代码 ```` import java.util.Scanner; public class Main { private static long num = 0; private stat ...
- 图解 HTTP, 图解 HTTPS, 图解 HTTP/2, 图解 HTTP/3, 图解 QUIC
图解 HTTP, 图解 HTTPS, 图解 HTTP/2, 图解 HTTP/3, 图解 QUIC HTTP https://en.wikipedia.org/wiki/Hypertext_Transf ...
- web development all in one
web development all in one https://javascript.xgqfrms.xyz/web-development-all-in-one.html refs https ...
- 如何重置电信悦 me 智能网关
如何重置电信悦 me 智能网关 重置电信网关密码 电信悦 me 智能网关密码忘记了怎么办? 首先,得要知道默认终端配置地址和默认终端配置密码. 可以从无线路由器背面标签得知. 如果不知道密码了,可以通 ...
- USDN代币多少钱?USDN有什么用?
加密货币走向主流人群的采用有很多障碍,比如监管.交易所黑客事件等,但最明显的障碍还是它们极端的价格波动.这从加密货币的整个历史长度来看都是如此.一个货币要正常运转,比如成为有效的交换媒介.记账单位以及 ...
- linux驱动系列之程序反汇编
摘抄网页:http://www.169it.com/article/330129798173630299.html 参考网页:http://www.cppblog.com/liu1061/articl ...