学习自:https://www.luogu.org/blog/user28084/solution-p3369
简述:看了一个下午+晚上搞出来的东西。
题目:
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
-
插入 x 数;
-
删除 x 数(若有多个相同的数,因只删除一个);
-
查询 x 数的排名(若有多个相同的数,因输出最小的排名);
-
查询排名为 x 的数;
-
求 x 的前趋(前趋定义为小于 x ,且最大的数);
-
求 x 的后继(后继定义为大于 x ,且最小的数)。
解题报告:代码即解释。
1 /*替罪羊树 2 您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作: 3 1.插入 x 数; 4 2.删除 x 数(若有多个相同的数,因只删除一个); 5 3.查询 x 数的排名(若有多个相同的数,因输出最小的排名); 6 4.查询排名为 x 的数; 7 5.求 x 的前趋(前趋定义为小于 x ,且最大的数); 8 6.求 x 的后继(后继定义为大于 x ,且最小的数)。*/ 9 #include<bits/stdc++.h> 10 #define numm ch-48 11 #define pd putchar(' ') 12 #define pn putchar('\n') 13 #define pb push_back 14 #define debug(args...) cout<<#args<<"->"<<args<<endl 15 #define bug cout<<"************" 16 using namespace std; 17 template <typename T> 18 void read(T &res) { 19 bool flag=false;char ch; 20 while(!isdigit(ch=getchar())) (ch=='-')&&(flag=true); 21 for(res=numm;isdigit(ch=getchar());res=(res<<1)+(res<<3)+numm); 22 flag&&(res=-res); 23 } 24 template <typename T> 25 void write(T x) { 26 if(x<0) putchar('-'),x=-x; 27 if(x>9) write(x/10); 28 putchar(x%10+'0'); 29 } 30 typedef long long ll; 31 typedef long double ld; 32 const int maxn=2e5+10; 33 const ll mod=1e9+7; 34 const int inf=0x3f3f3f3f; 35 const double alpha=0.7; 36 #define il inline 37 struct node { 38 int exist,son[2],sze,valid,val; 39 ///valid:当前子树的真实大小 40 ///sze:当前子树的虚假大小 41 ///exist:当前节点是否存在 42 ///val:当前节点的权值 43 ///son[0]:左儿子,son[1]:右儿子 44 }e[maxn]; 45 int memory[maxn],cur[maxn],mpos,cpos,to_rebuild,root; 46 ///memory[]:内存池(下标mpos);cur[]:存放要重建的树的中序遍历(下标cpos) 47 il bool isbad(int now) { ///以当前节点为根的子树是否需要重建 48 if((double)e[now].valid*alpha<=(double)max(e[e[now].son[0]].valid,e[e[now].son[1]].valid)) 49 return true; ///需要重建 50 else return false; 51 } 52 il void build(int l,int r,int &now) {///对有序序列进行重构二叉树 53 int mid=l+r>>1; 54 now=cur[mid]; ///每次都相当于把中间这个数提出来 55 if(l==r) { 56 e[now].son[0]=e[now].son[1]=0; 57 e[now].valid=e[now].sze=1; 58 return ; 59 } 60 if(l<mid) build(l,mid-1,e[now].son[0]); ///mid这个结点已经建完了 61 else e[now].son[0]=0; 62 build(mid+1,r,e[now].son[1]);///这里为什么不用判呢?想一下l=3,r=4的情况 63 e[now].sze=e[e[now].son[0]].sze+e[e[now].son[1]].sze+1; ///+1要划重点!!! 64 e[now].valid=e[e[now].son[0]].valid+e[e[now].son[1]].valid+1;///+1就是加本身 65 return ; 66 } 67 il void dfs(int now) { ///求中序遍历 68 if(!now) return ; 69 dfs(e[now].son[0]); ///中序遍历先遍历左子树 70 if(e[now].exist) cur[++cpos]=now;///存在的结点压入cur 71 else memory[++mpos]=now;///不存在的则回收 72 dfs(e[now].son[1]); 73 return ; 74 } 75 il void rebuild(int &now) {///重建二叉树 76 cpos=0; ///attention!!! 77 dfs(now); 78 if(cpos) build(1,cpos,now); 79 else now=0; ///没有要重建的,now=0 80 } 81 il void ins(int &now,int val) { ///插入一个数 82 if(!now) { 83 now=memory[mpos--]; ///分配一个空间给当前结点,作为它的下标 84 e[now].val=val; 85 e[now].exist=e[now].valid=e[now].sze=1; 86 e[now].son[0]=e[now].son[1]=0; 87 return ; 88 } 89 e[now].sze++,e[now].valid++; 90 if(val<=e[now].val) ins(e[now].son[0],val);///比当前的值大往右,否则往左 91 else ins(e[now].son[1],val); 92 if(!isbad(now)) { ///如果回溯到当前节点不用重建,就判断在它之前回溯的是否有需要重建的 93 if(to_rebuild) { 94 if(to_rebuild==e[now].son[0]) rebuild(e[now].son[0]);///判断左右子树哪个需要重建 95 else rebuild(e[now].son[1]); 96 to_rebuild=0; 97 } 98 } 99 else to_rebuild=now;///当前节点需要重建,先不重建,继续回溯 100 } 101 il int find_rnk(int val) {///查找权值为val对应的排名 102 int ans=1,now=root; 103 while(now) { 104 if(e[now].val>=val) now=e[now].son[0]; 105 else { ///下面两句话不要写颠倒!!! 106 ans+=e[e[now].son[0]].valid+e[now].exist; 107 now=e[now].son[1]; 108 } 109 } 110 return ans; 111 } 112 il int find_val(int k) { ///查找排名为k对应的权值 113 int now=root; 114 while(now) { 115 if(e[now].exist&&e[e[now].son[0]].valid+1==k) return e[now].val; 116 if(e[e[now].son[0]].valid>=k) now=e[now].son[0]; 117 else { ///下面两句话不要写颠倒!!! 118 k=k-e[e[now].son[0]].valid-e[now].exist; 119 now=e[now].son[1]; 120 } 121 } 122 } 123 il void del_rnk(int &now,int k) { ///删除排名为k的结点 124 if(e[now].exist&&e[e[now].son[0]].valid+1==k) {///当前的now为要找的结点 125 e[now].exist=0; 126 e[now].valid--; 127 return ; 128 } 129 e[now].valid--; 130 if(e[e[now].son[0]].valid+e[now].exist>=k) del_rnk(e[now].son[0],k); 131 else del_rnk(e[now].son[1],k-e[e[now].son[0]].valid-e[now].exist); 132 return ; 133 } 134 il void del_val(int val) { ///删除权值为val的数(删除靠左的第一个数) 135 del_rnk(root,find_rnk(val)); 136 if((double)e[root].sze*alpha>(double)e[root].valid) rebuild(root); ///如果删除的结点太多,则也需要重建 137 } 138 139 int main() 140 { 141 int n,op,val; 142 for(int i=1;i<=maxn-1;i++) 143 memory[i]=i; 144 while(scanf("%d",&n)!=EOF) { 145 root=to_rebuild=0; 146 e[0].valid=0; 147 mpos=(int)2e5-1; ///内存池下标初始化 148 for(int i=1;i<=n;i++) { 149 read(op);read(val); 150 if(op==1) 151 ins(root,val); 152 else if(op==2) 153 del_val(val); 154 else if(op==3) 155 write(find_rnk(val)),pn; 156 else if(op==4) 157 write(find_val(val)),pn; 158 else if(op==5) 159 write(find_val(find_rnk(val)-1)),pn; 160 ///find_rnk总会找到val最小的rnk,-1就是最后一个比它小的数的rnk 161 else if(op==6) 162 write(find_val(find_rnk(val+1))),pn; 163 ///找到比val小(包括val)的数的数量,直接查找该rnk对应的val 164 } 165 pn; 166 } 167 return 0; 168 }