Hihocoder 1329(splay)

Problem 平衡树 Splay

题目大意

  维护一个数列,支持三种操作。

  操作1:添加一个数x。

  操作2:询问不超过x的最大的数。

  操作三:删除大小在区间【a,b】内的数。

解题分析

  和上一题相比,多了一个删除的操作。

  首先将a的前驱节点x旋转到根,然后将b的后驱节点y旋转到x的右孩子,这样所有大小在【a,b】内的数均位于y的左子树内,直接将其删掉就可以了。

  为了防止找不到x和y,在初始化时向树中插入一个极大值和一个极小值。

参考程序

  1 #include <bits/stdc++.h>
  2 using namespace std;
  3
  4 struct node{
  5     int val;
  6     node *left,*right,*father;
  7     node(int val_=0,node* father_=NULL,node* left_=NULL,node* right_=NULL)
  8     {
  9         val=val_; father=father_; left=left_; right=right_;
 10     }
 11 }*rt,*t1,*t2;
 12
 13 void search(node *now)
 14 {
 15     cout<<now<<" "<<now->val<<" "<<now->left<<" "<<now->right<<" "<<now->father<<endl;
 16     if (now->left) search(now->left);
 17     if (now->right) search(now->right);
 18 }
 19
 20 void pushup(node *x)
 21 {
 22 }
 23
 24 void right(node* x,node* &rt)
 25 {
 26     node *y=x->father,*z=y->father;
 27     if (y==rt) rt=x;
 28     else if (z->left==y) z->left=x; else z->right=x; //需要判断是左右孩子
 29     x->father=z; y->father=x; if (x->right) x->right->father=y;  //防止对空指针进行操作
 30     y->left=x->right; x->right=y;
 31     pushup(y); pushup(x);
 32 }
 33
 34 void left(node* x,node* &rt)
 35 {
 36     node *y=x->father,*z=y->father;
 37     if (y==rt) rt=x;
 38     else if (z->left==y) z->left=x; else z->right=x;
 39     x->father=z; y->father=x; if (x->left) x->left->father=y;
 40     y->right=x->left; x->left=y;
 41     pushup(y); pushup(x);
 42 }
 43
 44 void splay(node* x,node* &rt)
 45 {
 46     while (x!=rt)
 47     {
 48         node *y=x->father, *z=y->father;
 49         if (y==rt)
 50         {
 51             if (x==y->left) right(x,rt);
 52             else left(x,rt);
 53         }
 54         else
 55         {
 56             if (y==z->left)
 57                 if (x==y->left) { right(y,rt); right(x,rt); }
 58                 else { left(x,rt); right(x,rt); }
 59             else
 60                 if (x==y->right) { left(y,rt); left(x,rt); }
 61                 else { right(x,rt); left(x,rt); }
 62         }
 63     }
 64 }
 65
 66 void insert(int val,node* &now,node *last)
 67 {
 68     if (now==NULL)
 69     {
 70         now=new node(val,last);
 71         splay(now,rt);
 72         return;
 73     }
 74     if (val < now->val) insert(val,now->left,now);  else  //else还是要加的 返回的时候树的形态已经改变了
 75     if (val > now->val) insert(val,now->right,now);
 76 }
 77
 78 int get(int val,node *x)
 79 {
 80     int res=-1<<30;
 81     while (x!=NULL)
 82     {
 83         if (x->val>val) x=x->left;
 84         else
 85         {
 86             res=max(res,x->val);
 87             x=x->right;
 88         }
 89     }
 90     return res;
 91 }
 92
 93 void find_1(int val,node *x)
 94 {
 95     if (x==NULL) return;
 96     if (x->val>=val) find_1(val,x->left);
 97     else {t1=x; find_1(val,x->right);}
 98 }
 99
100
101 void find_2(int val,node *x)
102 {
103     if (x==NULL) return;
104     if (x->val<=val) find_2(val,x->right);
105     else {t2=x; find_2(val,x->left);}
106 }
107
108 void work(int l,int r)
109 {
110     t1=t2=NULL;
111     find_1(l,rt); splay(t1,rt);
112     find_2(r,rt->right); splay(t2,rt->right);
113     rt->right->left=NULL;
114 }
115
116 int main()
117 {
118     int n;
119     rt=NULL;
120     scanf("%d",&n);
121     insert(1<<30,rt,NULL); insert(-1<<30,rt,NULL);
122     for (int i=1;i<=n;i++)
123     {
124         char s[3]; int x,y;
125         scanf("%s%d",s,&x);
126         if (s[0]==‘I‘) insert(x,rt,NULL);
127         if (s[0]==‘Q‘) cout<<get(x,rt)<<endl;
128         if (s[0]==‘D‘)
129         {
130             scanf("%d",&y);
131             if (x>y) swap(x,y);
132             work(x,y);
133         }
134     }
135 }

时间: 2024-10-22 18:06:40

Hihocoder 1329(splay)的相关文章

zoj 3612 Median (splay)

题目大意: 添加和删除一个数,然后输出中位数. 简单的Splay   维护Splay上有多少个节点就可以了 #include <cstdio> #include <iostream> #define inf 1LL<<60 #define maxn 222222 #define keyTree (ch[ch[root][1]][0]) using namespace std; typedef long long LL; int S[maxn],que[maxn],ch[

CF 295E Yaroslav and Points(Splay)

题目大意: 两个操作 1 id op  把id的位置+op 2 id op  查询在[id,op]之间的所有的数的差 思路: 关键是pushup函数. 自己退一下会发现,跟区间的总和,区间的节点个数有关. 比如如果左区间是 1 2 的话 右区间来一个 9 那么 就要加上 9-1+9-2 #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include

P3391 【模板】文艺平衡树(Splay)新板子

P3391 [模板]文艺平衡树(Splay) 题目背景 这是一道经典的Splay模板题——文艺平衡树. 题目描述 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[2,4]的话,结果是5 2 3 4 1 输入输出格式 输入格式: 第一行为n,m n表示初始序列有n个数,这个序列依次是(1,2, \cdots n-1,n)(1,2,?n−1,n) m表示翻转操作次数 接下来m行每行两个数 [l,r][l,

【BZOJ3506】排序机械臂(Splay)

[BZOJ3506]排序机械臂(Splay) 题面 神TMBZOJ没有题面,感谢SYC的题面 洛谷的题面也不错 题解 对于每次旋转的物体 显然可以预处理出来 现在只要模拟旋转操作就行了 至于在哪里放标记的问题 我只在第K大放会鬼.. 所以在Splay里面也放了一次(和LCT一样的) 然而我每次都把排到了正确位置的元素直接给删掉了... 所以跑的很慢很慢... #include<iostream> #include<cstdio> #include<cstdlib> #i

BZOJ 1251 序列终结者(Splay)

题目大意 网上有许多题,就是给定一个序列,要你支持几种操作:A.B.C.D.一看另一道题,又是一个序列要支持几种操作:D.C.B.A.尤其是我们这里的某人,出模拟试题,居然还出了一道这样的,真是没技术含量……这样 我也出一道题,我出这一道的目的是为了让大家以后做这种题目有一个“库”可以依靠,没有什么其他的意思.这道题目 就叫序列终结者吧.[问题描述] 给定一个长度为N的序列,每个序列的元素是一个整数(废话).要支持以下三种操作: 1. 将 [L, R] 这个区间内的所有数加上 V. 2. 将 [

HDU 4441 Queue Sequence(splay)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4441 题意:一个数列,三种操作:(1)插入:找到没在当前数列中的最小的正整数i,将其插在位置p之后,并将-i插入某个位置使得满足先进先出(i表示进,-i表示出),这个位置尽量靠右:(2)删除:删掉数字i以及-i:(3)询问:查询i和-i之间的数字的和. 思路:对于没在数列中的数字可以用一个set直接维护.i的插入是正常的splay操作.对于-i的插入,我们首先找到i之前有几个正数,比如有x个,那么-

【BZOJ】1251: 序列终结者(splay)

http://www.lydsy.com/JudgeOnline/problem.php?id=1251 不行..为什么写个splay老是犯逗,这次又是null的mx没有赋值-maxlongint... #include <cstdio> #include <cstring> #include <cmath> #include <string> #include <iostream> #include <algorithm> #inc

平衡树(splay)

求区间最大值模板 1 struct node{ 2 int f[maxn];//父亲结点 3 int ch[maxn][2];//左右孩子 4 int key[maxn];//结点i代表的数字 5 int cnt[maxn];//结点i出现的次数,也可以为全值.平衡树没有相同值的结点,所以如果出现了相同值时,cnt[i]++,或者cnt[i] += key[i] 6 int siz[maxn];//包括i的子树的大小 7 int val[maxn]; 8 int Max[maxn]; 9 int

HYSBZ 1588 营业额统计 (Splay)

题意:给出一个公司每一天的营业额,求每天的最小波动值之和.该天的最小波动值= min { 绝对值| 该天以前某一天的营业额-该天的营业额 | }.第一天的最小波动值就是其自己. 思路:Splay伸展树的入门题,仅有splay,insert,rotate这三个主要的函数而已. 将一个数字(营业额)插入树中,并把其splay到根位置,然后其前驱和后继中离它较近的一个用来求最小波动值.注意可能没有前驱/后继.对第一个数特别处理. 注意:此题的数据有缺陷,读入营业额之前先将变量清零. 1 #includ