Treap树 = tree+heap
数和堆的集合,每个节点有值val,也有优先级key,那么这棵树的形态就被确定了,和插入顺序无关了(有赖于优先级
避免退化成链:再生成节点时,随机生成优先级,然后插入时动态调整
有旋treap:依靠旋转来维持heap的平衡
1、FHQ treap又称无旋treap,没有旋转操作,使用分裂和合并两个操作维护树的平衡
struct node{
int l,r;
int val;
int key;
int size;
}tr[N];
int root,idx;
int newnode(int v){
}
void pushup(){ //向上更新
}
void split(int p,int v,int &x,int &y){ //分裂操作 注意在递归的过程中,连接了分裂后的新边
}
int merg(int x,int y){ //合并,根据key的大小,注意在递归的过程中,连接了分裂后的新边
}
void inser(int v){ //插入节点,先分裂,再合并,连续两次合并
}
void del(int v){ //删除操作,先分裂、再合并
}
int get_k(int p,int k){ //返回第k个节点
}
void get_pre(int v){ //找前驱
}
void get_suc(int v){ //找后继
}
void get_rank(int v){//排名
}
void get_val(int k){//数值
}


P3369 【模板】普通平衡树
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn=1e5+10;
struct node{
int l,r;
int val; //树的权值
int key; //堆的随机值
int size;
}tr[maxn];
int root,idx;
int newnode(int &x,int v){
x=++idx;
tr[x].val=v;
tr[x].key=rand();
tr[x].size=1;
}
void pushup(int p){ //向上更新
tr[p].size=tr[tr[p].l].size+tr[tr[p].r].size+1;
}
void split(int p,int v,int &x,int &y){ //分裂操作 注意在递归的过程中,连接了分裂后的新边
if(!p) {x=y=0;return;
}
if(tr[p].val<=v){
x=p;
split(tr[x].r,v,tr[x].r,y);
pushup(x);
}
else{
y=p;
split(tr[y].l,v,x,tr[y].l);
pushup(y);;
}
}
int merg(int x,int y){ //合并,根据key的大小,注意在递归的过程中,连接了分裂后的新边
if(!x||!y) return x+y;
if(tr[x].key<tr[y].key){
tr[x].r=merg(tr[x].r,y);
pushup(x);
return x;
}
else{
tr[y].l=merg(x,tr[y].l);
pushup(y);
return y;
}
}
void inser(int v){ //插入节点,先分裂,再合并,连续两次合并
int x,y,z;
split(root,v,x,y);
newnode(z,v);
root=merg(merg(x,z),y);
}
void del(int v){ //删除操作,先分裂、再合并
int x,y,z;
split(root,v,x,z);
split(x,v-1,x,y);
y=merg(tr[y].l,tr[y].r);
root=merg(merg(x,y),z);
}
//int get_k(int p,int k){ //返回第k个节点
//
//}
int getrank(int v){//排名
int x,y;
split(root,v-1,x,y);
int ans=tr[x].size+1;
root=merg(x,y);
return ans;
}
int getval(int root,int v){//数值
if(v==tr[tr[root].l].size+1) return tr[root].val;
else if(v<=tr[tr[root].l].size) return getval(tr[root].l,v);
else return getval(tr[root].r,v-tr[tr[root].l].size-1);
}
int getpre(int v){ //找前驱
int x,y,s,ans;
split(root,v-1,x,y);
s=tr[x].size;
ans=getval(x,s);
root=merg(x,y);
return ans;
}
int getnex(int v){ //找后继
int x,y,ans;
split(root,v,x,y);
ans=getval(y,1);
root=merg(x,y);
return ans;
}
int main(){
int n,op,v;
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d %d",&op,&v);
if(op==1) inser(v);
else if(op==2) del(v);
else if(op==3) printf("%d\n",getrank(v));
else if(op==4) printf("%d\n",getval(root,v));
else if(op==5) printf("%d\n",getpre(v));
else printf("%d\n",getnex(v));
}
return 0;
}
文艺平衡树
还是有旋转操作的
// Luogu P3391 【模板】文艺平衡树
#include <iostream>
using namespace std;
const int N=100010;
struct node{
int l,r; //左右儿子
int val; //树的权值
int key; //堆的随机值
int size; //子树大小
int tag; //懒标记
}tr[N];
int n,m,root,idx;
int newnode(int v){
tr[++idx].val=v;
tr[idx].key=rand();
tr[idx].size=1;
return idx;
}
void pushup(int p){
tr[p].size=tr[tr[p].l].size
+tr[tr[p].r].size+1;
}
void pushdown(int p){
if(!tr[p].tag||!p) return;
swap(tr[p].l, tr[p].r);
tr[tr[p].l].tag ^= 1;
tr[tr[p].r].tag ^= 1;
tr[p].tag = 0;
}
void split(int p,int k,int &x,int &y){
if(!p) {x=y=0; return;}
pushdown(p);
if(k>tr[tr[p].l].size){
k-=tr[tr[p].l].size+1;
x=p;
split(tr[p].r,k,tr[p].r,y);
}
else{
y=p;
split(tr[p].l,k,x,tr[p].l);
}
pushup(p);
}
int merge(int x,int y){
if(!x||!y) return x+y;
if(tr[x].key<tr[y].key){
pushdown(x);
tr[x].r=merge(tr[x].r,y);
pushup(x); return x;
}
else{
pushdown(y);
tr[y].l=merge(x,tr[y].l);
pushup(y); return y;
}
}
void reverse(int l,int r){
int x,y,z;
split(root,r,x,z);
split(x,l-1,x,y);
tr[y].tag ^= 1; //标记
root=merge(merge(x,y),z);
}
void output(int p){
if(!p) return;
pushdown(p);
output(tr[p].l);
printf("%d ",tr[p].val);
output(tr[p].r);
}
int main(){
srand(time(0));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
root=merge(root,newnode(i));
for(int x,y,i=1;i<=m;i++){
scanf("%d%d",&x,&y);
reverse(x, y);
}
output(root);
return 0;
}
删除:如果有两个子节点,找到优先级大的,把x向反方向旋转,也就是把x向树的下层调整,直到旋转到叶子节点
!很多题目涉及名次树
常用操作:
struct node,旋转rotate,插入insert(),查找第k大的数kth(),查询某个数find()【名次树】
少林 hdu 4585
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll inf = 4e18+10;
const int mod = 1000000007;
const int mx = 5e6+5; //check the limits, dummy
typedef pair<int, int> pa;
const double PI = acos(-1);
ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; }
#define swa(a,b) a^=b^=a^=b
#define re(i,a,b) for(int i=(a),_=(b);i<_;i++)
#define rb(i,a,b) for(int i=(b),_=(a);i>=_;i--)
#define clr(a) memset(a, 0, sizeof(a))
#define lowbit(x) ((x)&(x-1))
#define mkp make_pair
void sc(int& x) { scanf("%d", &x); }void sc(int64_t& x) { scanf("%lld", &x); }void sc(double& x) { scanf("%lf", &x); }void sc(char& x) { scanf(" %c", &x); }void sc(char* x) { scanf("%s", x); }
int m, n,k,sum=0,ans=0,t;
int id[mx];
struct node
{
int size;//以这个节点为根的子树的节点总数,用于名次树
int rank;//优先级
int key;//键值
node *son[2];//son[0]左儿子,son[1]右儿子
bool operator<(const node& a)const { return rank < a.rank;}
int cmp(int x)const {
if (x == key)return -1;
return x < key ? 0 : 1;
}
void update() {
size = 1;
if (son[0] != NULL)size += son[0]->size;
if (son[1] != NULL)size += son[1]->size;
}
};
void rotate(node* &o, int d) {//d=0,左旋,d=1,右旋
node *k = o->son[d ^ 1];//d^1等价于1-d,但是更快
o->son[d ^ 1] = k->son[d];
k->son[d] = o;
o->update();
k->update();
o = k;
}
void insert(node* &o, int x) {//把x插入树中
if (o == NULL) {
o = new node();
o->son[0] = o->son[1] = NULL;
o->rank = rand();
o->key = x;
o->size = 1;
}
else {
int d = o->cmp(x);
insert(o->son[d],x);
o->update();
if (o < o->son[d]);
rotate(o, d ^ 1);
}
}
int kth(node* o, int k) {//返回第k大的数
if (o == NULL || k <= 0 || k > o->size)
return -1;
int s = o->son[1] == NULL ? 0 : o->son[1]->size;
if (k == s + 1)return o->key;
else if (k <= s)return kth(o->son[1], k);
else return kth(o->son[0], k - s - 1);
}
int find(node* o, int k) {//返回元素k的名次
if (o == NULL)
return -1;
int d = o->cmp(k);
if (d == -1)
return o->son[1] == NULL ? 1 : o->son[1]->size + 1;
else if (d == 1)return find(o->son[d],k);
else {
int tmp = find(o->son[d], k);
if (tmp == -1)
return -1;
else {
return o->son[1] == NULL ? tmp + 1 : tmp + 1 + o ->son[1]->size;
}
}
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
while (cin>>n&&n)
{
srand(time(NULL));
int k, g;
cin >> k >> g;
node* root = new node();
root->son[0] = root-> son[1] = NULL;
root->rank = rand();
root->key = g;
root->size = 1;
id[g] = k;
cout << k << ' ' << 1<<endl;
re(i, 2, n + 1) {
cin >> k >> g;
id[g] = k;
insert(root, g);
t = find(root, g);//返回新和尚的名次
int ans1, ans2;
ans1 = kth(root, t - 1);//前一名的老和尚
ans2 = kth(root, t + 1);//后一名的老和尚
if (ans1 != -1 && ans2 != -1)
{
ans = ans1 - g >= g - ans2 ? ans2 : ans1;
}
else if (ans1 == -1)
ans = ans2;
else ans = ans1;
cout << k << ' ' << id[ans] << endl;
}
}
return 0;
}
posted on
浙公网安备 33010602011771号