BZOJ_3224 Tyvj 1728 普通平衡树 【离散化+权值线段树】
一 题面
二 分析
比较明显是可以用平衡二叉搜索树(splay)做的。
用权值线段树做,前提就是要先离散化,因为权值线段树维护的值域信息。
板子。
三 AC代码
1 #include <iostream> 2 #include <algorithm> 3 #include <cstring> 4 #include <fstream> 5 6 using namespace std; 7 #define lson rt<<1 8 #define rson rt<<1|1 9 10 const int MAXN = 1e5 + 15; 11 int N, op[MAXN], opx[MAXN]; 12 struct Node 13 { 14 int id, x; 15 }Data[MAXN]; 16 int A[MAXN]; 17 18 int segTree[MAXN<<2]; 19 20 bool Cmpx(const Node &a, const Node &b) 21 { 22 return a.x < b.x; 23 } 24 25 //p更新的位置,v=-1表示减,v=1表示加 26 void Update(int p, int v, int rt, int l, int r) 27 { 28 segTree[rt] += v; 29 if(l == r) return; 30 int mid = (l+r)>>1; 31 if(p <= mid) Update(p, v, lson, l, mid); 32 else Update(p, v, rson, mid+1, r); 33 } 34 //第K小 35 int Kth(int K, int rt, int l, int r) 36 { 37 if(l == r) 38 return l; 39 int mid = (l+r)>>1; 40 if(segTree[lson] >= K) 41 return Kth(K, lson, l, mid); 42 else 43 return Kth(K-segTree[lson], rson, mid+1, r); 44 } 45 //数字v的排名 46 //统计小于v的数的个数 47 int Rank(int v, int rt, int l, int r) 48 { 49 if(r < v) 50 return segTree[rt]; 51 int mid = (l+r)>>1, res = 0; 52 res += Rank(v, lson, l, mid); 53 //相当于mid+1 < v 那么左边可能还有 54 if(mid < v-1) 55 res += Rank(v, rson, mid+1, r); 56 return res; 57 } 58 //找最右边的数 59 int Findr(int rt, int l, int r) 60 { 61 if(l == r) 62 return l; 63 int mid = (l+r)>>1; 64 if(segTree[rson]) return Findr(rson, mid + 1, r); 65 return Findr(lson, l, mid); 66 } 67 //前驱 68 int Pre(int v, int rt, int l, int r) 69 { 70 if(r < v) 71 { 72 if(segTree[rt]) return Findr(rt, l, r); 73 return 0; 74 } 75 int mid = (l+r)>>1, res; 76 //如果v > mid+1那么意味着mid+1或后面的数有可能是前驱 77 if(mid < v-1 && segTree[rson] && (res=Pre(v,rson,mid+1,r))) 78 return res; 79 return Pre(v, lson, l, mid); 80 } 81 //找最左边的数 82 int Findl(int rt, int l, int r) 83 { 84 if(l == r) 85 return l; 86 int mid = (l+r)>>1; 87 if(segTree[lson]) return Findl(lson, l, mid); 88 return Findl(rson, mid+1, r); 89 } 90 //后继 91 int Nex(int v, int rt, int l, int r) 92 { 93 if(v < l) 94 { 95 if(segTree[rt]) return Findl(rt, l, r); 96 return 0; 97 } 98 int mid = (l+r)>>1, res; 99 //如果mid > v表示左子树的数可能是后继 100 if(v < mid && segTree[lson] && (res=Nex(v,lson,l,mid))) 101 return res; 102 return Nex(v, rson, mid + 1, r); 103 } 104 105 int main() 106 { 107 //freopen("input.txt", "r", stdin); 108 scanf("%d", &N); 109 for(int i = 1; i <= N; i++) 110 { 111 scanf("%d %d", &op[i], &Data[i].x); 112 Data[i].id = i; 113 } 114 //离散化预处理 115 sort(Data + 1, Data + N + 1, Cmpx); 116 int cnt = 1; 117 A[cnt] = Data[1].x; 118 opx[Data[1].id] = cnt; 119 for(int i = 2; i <= N; i++) 120 { 121 if(Data[i].x != Data[i - 1].x) 122 { 123 cnt++; 124 } 125 A[cnt] = Data[i].x; 126 opx[Data[i].id] = cnt; 127 } 128 //建树 129 memset(segTree, 0, sizeof(segTree) ); 130 for(int i = 1; i <= N; i++) 131 { 132 switch(op[i]) 133 { 134 case 1: Update(opx[i], 1, 1, 1, cnt); break; 135 case 2: Update(opx[i], -1, 1, 1, cnt); break; 136 case 3: printf("%d\n", Rank(opx[i], 1, 1, cnt)+1); break; 137 //这里注意第K个数也离散化了!!! 138 case 4: printf("%d\n", A[ Kth(A[opx[i]], 1, 1, cnt)] ); break; 139 case 5: printf("%d\n", A[ Pre(opx[i], 1, 1, cnt)] ); break; 140 case 6: printf("%d\n", A[ Nex(opx[i], 1, 1, cnt)] ); break; 141 } 142 } 143 144 return 0; 145 }