BZOJ 3224 Tyvj 1728 普通平衡树模板
题目链接:
https://www.lydsy.com/JudgeOnline/problem.php?id=3224
题目大意:
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
1. 插入x数
2. 删除x数(若有多个相同的数,因只删除一个)
3. 查询x数的排名(若有多个相同的数,因输出最小的排名)
4. 查询排名为x的数
5. 求x的前驱(前驱定义为小于x,且最大的数)
6. 求x的后继(后继定义为大于x,且最小的数)
思路:
splay:http://www.cnblogs.com/BCOI/p/9010229.html
treap:https://www.cnblogs.com/BCOI/p/9072444.html
1 #include<bits/stdc++.h> 2 #define IOS ios::sync_with_stdio(false);//不可再使用scanf printf 3 #define Max(a, b) ((a) > (b) ? (a) : (b))//禁用于函数,会超时 4 #define Min(a, b) ((a) < (b) ? (a) : (b)) 5 #define Mem(a) memset(a, 0, sizeof(a)) 6 #define Dis(x, y, x1, y1) ((x - x1) * (x - x1) + (y - y1) * (y - y1)) 7 #define MID(l, r) ((l) + ((r) - (l)) / 2) 8 #define lson ((o)<<1) 9 #define rson ((o)<<1|1) 10 #pragma comment(linker, "/STACK:102400000,102400000")//栈外挂 11 using namespace std; 12 inline int read() 13 { 14 int x=0,f=1;char ch=getchar(); 15 while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();} 16 while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 17 return x*f; 18 } 19 20 typedef long long ll; 21 const int maxn = 1000000 + 10; 22 const int MOD = 1000000007;//const引用更快,宏定义也更快 23 const int INF = 1e9 + 7; 24 const double eps = 1e-6; 25 26 struct node 27 { 28 int fa;//记录父节点 29 int ch[2];//ch[0]表示左儿子 ch[1]表示右儿子 30 int val;//节点权值 31 int Size;//记录节点子树大小(包括该节点) 32 int cnt;//记录同样权值的元素个数 33 int mark;//记录反转区间标记(普通平衡树不用) 34 }t[maxn]; 35 int root = 0;//根节点 36 int cnt = 0;//当前节点数目 37 bool get(int x)//判断一个节点是左节点还是右节点 38 { 39 return t[t[x].fa].ch[1] == x;//右节点返回1 左节点返回0 40 } 41 void up(int x)//重新统计节点x的size 42 { 43 t[x].Size = t[t[x].ch[0]].Size + t[t[x].ch[1]].Size + t[x].cnt; 44 } 45 void Rotate(int x)//节点x与父节点旋转 46 { 47 int fa = t[x].fa, gfa = t[fa].fa; 48 int d1 = get(x), d2 = get(fa);//加上d1 d2均表示左儿子 49 t[fa].ch[d1] = t[x].ch[d1 ^ 1]; t[t[x].ch[d1 ^ 1]].fa = fa;//父节点的左儿子设置成左儿子的右儿子(双向设置) 50 t[gfa].ch[d2] = x; t[x].fa = gfa;//祖父节点的左儿子设置成父节点的左儿子(双向) 51 t[fa].fa = x; t[x].ch[d1^1] = fa;//左儿子的右儿子设置成父节点(双向) 52 up(fa); up(x); 53 } 54 void splay(int x, int goal)//x旋转到goal下面 55 { 56 while(t[x].fa != goal) 57 { 58 int fa = t[x].fa, gfa = t[fa].fa; 59 int d1 = get(x), d2 = get(fa); 60 if(gfa != goal) 61 { 62 if(d1 == d2)Rotate(fa);//同侧,先旋父节点(双旋) 63 else Rotate(x);//异侧 直接选 64 } 65 Rotate(x);//再向上旋一次 66 } 67 if(goal == 0)root = x; 68 } 69 void Insert(int val) 70 { 71 int node = root, fa = 0; 72 while(node && t[node].val != val) 73 fa = node, node = t[node].ch[t[node].val < val]; 74 if(node)t[node].cnt++;//节点存在 75 else 76 { 77 node = ++cnt; 78 if(fa)t[fa].ch[t[fa].val < val] = node; 79 t[node].fa = fa; 80 t[node].Size = t[node].cnt = 1; 81 t[node].val = val; 82 } 83 splay(node, 0);//将新节点旋到根来维护splay的子树 84 } 85 int kth(int k)//查询第k大的数 86 { 87 int node = root; 88 while(1) 89 { 90 int son = t[node].ch[0]; 91 if(k <= t[son].Size)node = son; 92 else if(k > t[son].Size + t[node].cnt) 93 { 94 k -= t[son].Size + t[node].cnt; 95 node = t[node].ch[1]; 96 } 97 else return t[node].val; 98 } 99 } 100 int Find(int val)//直接调用Find(INF)或者调用Find(-INF)可以得到最大值和最小值编号 101 { 102 int node = root; 103 while(t[node].val != val && t[node].ch[t[node].val < val]) 104 node = t[node].ch[t[node].val < val]; 105 return node; 106 } 107 int get_rank(int val)//查询一个数的排名 108 { 109 splay(Find(val), 0); 110 return t[t[root].ch[0]].Size + 1; 111 } 112 int get_pre(int val, int kind)//kind = 0 查询前驱 kind = 1查询后继 113 { 114 splay(Find(val), 0); 115 int node = root; 116 if(t[node].val < val && kind == 0)return node; 117 if(t[node].val > val && kind == 1)return node;//根节点就是前驱/后继的情况 118 node = t[node].ch[kind]; 119 while(t[node].ch[kind ^ 1])node = t[node].ch[kind ^ 1];//否则在子树中寻找最值 120 return node;//返回的是编号 具体的值调用需要用t[node].val 121 } 122 void delet(int val) 123 { 124 int last = get_pre(val, 0);//由于此处查询了前驱和后缀 可能会查询到最小值的前驱或者最大值的后缀 125 int next = get_pre(val, 1);//必须事先加入INF 和-INF 不然会出错 126 splay(last, 0); 127 splay(next, last); 128 if(t[t[next].ch[0]].cnt > 1) 129 { 130 t[t[next].ch[0]].cnt--; 131 splay(t[next].ch[0], 0); 132 } 133 else t[next].ch[0] = 0; 134 } 135 int main() 136 { 137 int n, x, y; 138 Insert(-INF); 139 Insert(INF); 140 scanf("%d", &n); 141 while(n--) 142 { 143 scanf("%d%d", &x, &y); 144 if(x == 1)Insert(y); 145 if(x == 2)delet(y); 146 if(x == 3)printf("%d\n", get_rank(y)- 1);//排名减一是因为要减去负无穷这个数 147 if(x == 4)printf("%d\n", kth(y + 1));//排名是y+1 因为加上负无穷这个数 148 if(x == 5)printf("%d\n", t[get_pre(y, 0)].val); 149 if(x == 6)printf("%d\n", t[get_pre(y, 1)].val); 150 } 151 return 0; 152 }
越努力,越幸运