##3224: Tyvj 1728 普通平衡树
Description
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
- 插入x数
- 删除x数(若有多个相同的数,因只删除一个)
- 查询x数的排名(若有多个相同的数,因输出最小的排名)
- 查询排名为x的数
- 求x的前驱(前驱定义为小于x,且最大的数)
- 求x的后继(后继定义为大于x,且最小的数)
Input
第一行为n,表示操作的个数,下面n行每行有两个数opt和x,opt表示操作的序号(1<=opt<=6)
Output
对于操作3,4,5,6每行输出一个数,表示对应答案
Sample Input
10
1 106465
4 1
1 317721
1 460929
1 644985
1 84185
1 89851
6 81968
1 492737
5 493598
Sample Output
106465
84185
492737
HINT
1.n的数据范围:n<=100000
2.每个数的数据范围:[-2e9,2e9]
暂时没决定模板
#include<cstdio>
struct SBT{
int son[2],cnt,v,size;
}e[100005];
int n,cnt,root,ans;
inline void rotate( int &k, bool f ){
int p = e[k].son[f]; e[k].son[f] = e[p].son[!f]; e[p].son[!f] = k;
e[k].size = e[e[k].son[1]].size + e[e[k].son[0]].size + e[k].cnt;
e[p].size = e[e[p].son[1]].size + e[e[p].son[0]].size + e[p].cnt;
k = p;
}
void maintain( int &k,bool f ){
if(!k) return;
if(e[e[k].son[!f]].size < e[e[e[k].son[f]].son[f]].size)
rotate(k, f);
else if(e[e[k].son[!f]].size < e[e[e[k].son[f]].son[!f]].size) {
rotate(e[k].son[f], !f); rotate(k, f);
}
else return;
maintain(e[k].son[f],f);
maintain(k,f);
}
void insert( int &k, int x ){
if(!k){
k = ++cnt;
e[k].size = e[k].cnt = 1;
e[k].v = x;
return ;
}
e[k].size++;
if( e[k].v == x ) {
e[k].cnt++;
return ;
}
insert(e[k].son[e[k].v<x],x);
maintain(k,e[k].v<x);
}
int del( int &k, int x ){
if(!k) return k;
int tmp;
if( e[k].v == x ){
if( e[k].cnt > 1 ){
e[k].size--; e[k].cnt--;
return k;
}else if( !(e[k].son[0]*e[k].son[1]) ){
k = e[k].son[0] + e[k].son[1];
}else {
tmp = del(e[k].son[0],x+1);
e[k].cnt = e[tmp].cnt;
e[k].v = e[tmp].v;
e[k].size = e[e[k].son[1]].size + e[e[k].son[0]].size + e[k].cnt;
return k;
}
} else if( (e[k].v<x && !e[k].son[1])||(e[k].v>x && !e[k].son[0])){
tmp=k;k=e[k].son[0];
e[k].size = e[e[k].son[0]].size + e[e[k].son[1]].size + e[k].cnt;
return tmp;
}
else tmp = del(e[k].son[e[k].v<x],x);
e[k].size = e[e[k].son[0]].size + e[e[k].son[1]].size + e[k].cnt;
return tmp;
}
int rank( int k, int x ){
if( k == 0 ) return 0;
if( e[k].v == x ) return e[e[k].son[0]].size+1;
else if( x > e[k].v ) return e[e[k].son[0]].size + e[k].cnt + rank(e[k].son[1],x);
else return rank(e[k].son[0],x);
}
int kth( int k, int x ){
if( k == 0 ) return 0;
if( x <= e[e[k].son[0]].size ) return kth(e[k].son[0],x);
else if( x > e[e[k].son[0]].size + e[k].cnt ) return kth(e[k].son[1],x-e[e[k].son[0]].size-e[k].cnt);
else return e[k].v;
}
void pred( int k, int x ){
if( k == 0 ) return ;
if( e[k].v < x ){
ans = e[k].v;
pred(e[k].son[1],x);
}
else pred(e[k].son[0],x);
}
void succ( int k, int x ){
if( k == 0 ) return ;
if( e[k].v > x ){
ans = e[k].v;
succ(e[k].son[0],x);
}
else succ(e[k].son[1],x);
}
int main(){
scanf("%d", &n);
int opt,x;
for( int i = 1; i <= n; i++ ){
scanf("%d%d", &opt, &x);
switch(opt) {
case 1: insert(root,x); break;
case 2: del(root,x); break;
case 3: printf("%d\n",rank(root,x)); break;
case 4: printf("%d\n",kth(root,x)); break;
case 5: ans=0; pred(root,x); printf("%d\n",ans); break;
case 6: ans=0; succ(root,x); printf("%d\n",ans); break;
}
}
return 0;
}
7.26
替罪羊树是一棵子树不平衡,就暴力重建的树
时间很理想
是不用旋转的BST
因此可以套线段树
#include<bits/stdc++.h>
#define a 0.7
using namespace std;
const int inf = 0x7fffffff;
const int N = 1000000 + 5;
int n, m, q, sz, cnt, c[N][2], far[N], root, sum[N], siz[N], val[N], mx[N], dfn[N];
void init(){
sz = 2; root = 1;
val[1] = -inf; siz[1] = 2; c[1][1] = 2;
val[2] = inf; siz[2] = 1; far[2] = 1;
}
bool check( int k ) { return (double)siz[k] * a >= (double)siz[c[k][0]] && (double)siz[k] * a >= (double)siz[c[k][1]]; }
void dfs( int k ){
if( c[k][0] ) dfs( c[k][0] );
dfn[++cnt] = k;//zheli k he cnt gaofanle
if( c[k][1] ) dfs( c[k][1] );
}
int build( int l, int r ){
if( l > r ) return 0;
int mid = l + r >> 1, fa = dfn[mid];
far[c[fa][0] = build(l, mid - 1)] = fa;
far[c[fa][1] = build(mid + 1, r)] = fa;
siz[fa] = siz[c[fa][0]] + siz[c[fa][1]] + 1;
return fa;
}
void rebuild( int k ){
cnt = 0; dfs(k);
int y = far[k], lr = (k == c[y][1]);
int now = build( 1, cnt );
far[c[y][lr] = now] = y;
if( k == root ) root = now;
}
void insert( int x ){
int now = root, nd = ++sz, unv = 0;
siz[nd] = 1; val[nd] = x;
while( 1 ){
siz[now]++;
bool lr = ( x >= val[now] );
if( c[now][lr] ) now = c[now][lr];
else{ far[c[now][lr] = nd] = now; break; }
}
for( int i = nd; i; i = far[i] ) if( !check(i) ) unv = i;
if( unv ) rebuild( unv );
}
int rank( int x ){
int now = root, rk = 0;
while( now ){
if( val[now] < x ) rk += siz[c[now][0]] + 1, now = c[now][1];
else now = c[now][0];
}
return rk;
}
int kth( int k ){
int now = root;
while( 1 ){
if( siz[c[now][0]] == k - 1 ) return now;
else if( siz[c[now][0]] >= k ) now = c[now][0];
else k -= siz[c[now][0]] + 1, now = c[now][1];
}
return now;
}
int getn( int x ){
int now = root;
while( 1 ){
if( val[now] == x ) return now;
else now = c[now][x > val[now]];
}
}
void delet( int k ){
if( c[k][0] && c[k][1] ){
int nd = c[k][0];
while( c[nd][1] ) nd = c[nd][1];
val[k] = val[nd];
k = nd;
}
int son = c[k][0] ? c[k][0] : c[k][1], ws = c[far[k]][1] == k;
far[c[far[k]][ws] = son] = far[k];
for( int i = far[k]; i; i = far[i] ) siz[i]--;
if( k == root ) root = son;
}
int succ( int x ){
int now = root, ans = inf;
while( now ){
if( val[now] > x ) ans = min( ans, val[now] ), now = c[now][0];
else now = c[now][1];
}
return ans;
}
int pred( int x ){
int now = root, ans = -inf;
while( now ){
if( val[now] < x ) ans = max( ans, val[now] ), now = c[now][1];
else now = c[now][0];
}
return ans;
}
int main(){
init();
scanf("%d", &n);
for( int i = 1, opt, x; i <= n; i++ ){
scanf( "%d%d", &opt, &x );
if( opt == 1 ) insert( x );
if( opt == 2 ) delet( getn(x) );
if( opt == 3 ) printf("%d\n", rank(x));
if( opt == 4 ) printf("%d\n", val[kth(x + 1)]);
if( opt == 5 ) printf("%d\n", pred(x));
if( opt == 6 ) printf("%d\n", succ(x));
}
return 0;
}