study from:
https://tiger0132.blog.luogu.org/slay-notes
1 #include2 #include 3 #include 4 #include 5 #include <string> 6 #include 7 #include 8 using namespace std; 9 #define ll long long 10 11 const double eps=1e-8; 12 const ll inf=1e9; 13 const ll mod=1e9+7; 14 const int maxn=1e5+10; 15 16 int par[maxn],son[maxn][2],siz[maxn],val[maxn],cnt[maxn],root,id; 17 18 int chk(int x) 19 { 20 return son[par[x]][1]==x; 21 } 22 23 void pushup(int x) 24 { 25 siz[x]=siz[son[x][0]]+siz[son[x][1]]+cnt[x]; 26 } 27 28 void rotate(int x) 29 { 30 int y=par[x]; 31 int z=par[y]; 32 int k=chk(x); 33 int w=son[x][k^1]; 34 son[y][k]=w,par[w]=y; 35 son[z][chk(y)]=x,par[x]=z; 36 son[x][k^1]=y,par[y]=x; 37 pushup(y),pushup(x); 38 } 39 40 void splay(int x,int goal=0) 41 { 42 int y,z; 43 while (par[x]!=goal) 44 { 45 y=par[x]; 46 z=par[y]; 47 if (z!=goal) 48 { 49 if (chk(x)==chk(y)) 50 rotate(y); 51 else 52 rotate(x); 53 } 54 rotate(x); 55 } 56 if (!goal) 57 root=x; 58 } 59 60 void find(int x) 61 { 62 if (!root) 63 return; 64 int cur=root; 65 while (son[cur][x>val[cur]] && x!=val[cur]) 66 cur=son[cur][x>val[cur]]; 67 splay(cur); ///用于找到排名,前继,后继 68 } 69 70 void insert(int x) 71 { 72 int cur=root,p=0; 73 while (cur && val[cur]!=x) 74 { 75 p=cur; 76 cur=son[cur][x>val[cur]]; 77 } 78 if (cur) 79 cnt[cur]++; 80 else 81 { 82 cur=++id; 83 if (p) 84 { 85 son[p][x>val[p]]=cur; 86 siz[p]++; ///不写也行,在splay(cur)中会更改 87 } 88 son[cur][0]=son[cur][1]=0; 89 val[cur]=x; 90 par[cur]=p; 91 cnt[cur]=siz[cur]=1; 92 } 93 splay(cur); ///保持平衡 94 } 95 96 int kth(int k) 97 { 98 int cur=root; 99 while (1) 100 { 101 if (son[cur][0] && k<=siz[son[cur][0]]) 102 cur=son[cur][0]; 103 else if (k>siz[son[cur][0]]+cnt[cur]) 104 { 105 k-=siz[son[cur][0]]+cnt[cur]; 106 cur=son[cur][1]; 107 } 108 else 109 return cur; 110 } 111 } 112 113 void x_rank(int x) 114 { 115 find(x); 116 if (val[root]>=x) ///根节点所在的值不选用 117 printf("%d\n",siz[son[root][0]]+1-1); ///最小的点 118 else 119 printf("%d\n",siz[son[root][0]]+cnt[root]+1-1); ///最小的点 120 } 121 122 int pre(int x) 123 { 124 find(x); 125 if (val[root]<x) 126 return root; 127 int cur=son[root][0]; 128 while (son[cur][1]) 129 cur=son[cur][1]; 130 return cur; 131 } 132 133 int succ(int x) 134 { 135 find(x); 136 if (val[root]>x) 137 return root; 138 int cur=son[root][1]; 139 while (son[cur][0]) 140 cur=son[cur][0]; 141 return cur; 142 } 143 144 void remove(int x) 145 { 146 int last=pre(x); 147 int next=succ(x); 148 splay(last); 149 splay(next,last); 150 int del=son[next][0]; ///有且只有一个节点 151 if (cnt[del]>1) 152 { 153 cnt[del]--; 154 splay(del); 155 } 156 else 157 son[next][0]=0; ///删除该节点 158 pushup(next),pushup(root); 159 } 160 161 int main() 162 { 163 int t,mode,x;
164 insert(0xefefefef); ///增加最小的点,pre也许不存在 165 insert(0x3f3f3f3f); ///增加最大的点,succ也许不存在 166 scanf("%d",&t); 167 while (t--) 168 { 169 scanf("%d%d",&mode,&x); 170 if (mode==1) 171 insert(x); 172 else if (mode==2) 173 remove(x); 174 else if (mode==3) 175 x_rank(x); 176 else if (mode==4) 177 printf("%d\n",val[kth(x+1)]); ///最小的点 178 else if (mode==5) 179 printf("%d\n",val[pre(x)]); 180 else if (mode==6) 181 printf("%d\n",val[succ(x)]); 182 } 183 return 0; 184 }
考虑到刚访问的节点在之后有可能很快将再次访问
1 #include2 #include 3 #include 4 #include 5 #include <string> 6 #include 7 #include 8 using namespace std; 9 #define ll long long 10 11 const double eps=1e-8; 12 const ll inf=1e9; 13 const ll mod=1e9+7; 14 const int maxn=1e5+10; 15 16 int par[maxn],son[maxn][2],siz[maxn],val[maxn],cnt[maxn],root,id; 17 18 int chk(int x) 19 { 20 return son[par[x]][1]==x; 21 } 22 23 void pushup(int x) 24 { 25 siz[x]=siz[son[x][0]]+siz[son[x][1]]+cnt[x]; 26 } 27 28 void rotate(int x) 29 { 30 int y=par[x]; 31 int z=par[y]; 32 int k=chk(x); 33 int w=son[x][k^1]; 34 son[y][k]=w,par[w]=y; 35 son[z][chk(y)]=x,par[x]=z; 36 son[x][k^1]=y,par[y]=x; 37 pushup(y),pushup(x); 38 } 39 40 void splay(int x,int goal=0) 41 { 42 int y,z; 43 while (par[x]!=goal) 44 { 45 y=par[x]; 46 z=par[y]; 47 if (z!=goal) 48 { 49 if (chk(x)==chk(y)) 50 rotate(y); 51 else 52 rotate(x); 53 } 54 rotate(x); 55 } 56 if (!goal) 57 root=x; 58 } 59 60 void find(int x) 61 { 62 if (!root) 63 return; 64 int cur=root; 65 while (son[cur][x>val[cur]] && x!=val[cur]) 66 cur=son[cur][x>val[cur]]; 67 splay(cur); 68 } 69 70 void insert(int x) 71 { 72 int cur=root,p=0; 73 while (cur && val[cur]!=x) 74 { 75 p=cur; 76 cur=son[cur][x>val[cur]]; 77 } 78 if (cur) 79 cnt[cur]++; 80 else 81 { 82 cur=++id; 83 if (p) 84 son[p][x>val[p]]=cur; 85 son[cur][0]=son[cur][1]=0; 86 val[cur]=x; 87 par[cur]=p; 88 cnt[cur]=siz[cur]=1; 89 } 90 splay(cur); 91 } 92 93 int kth(int k) 94 { 95 int cur=root; 96 while (1) 97 { 98 if (son[cur][0] && k<=siz[son[cur][0]]) 99 cur=son[cur][0]; 100 else if (k>siz[son[cur][0]]+cnt[cur]) 101 { 102 k-=siz[son[cur][0]]+cnt[cur]; 103 cur=son[cur][1]; 104 } 105 else 106 { 107 splay(cur); 108 return cur; 109 } 110 } 111 } 112 113 void x_rank(int x) 114 { 115 find(x); 116 if (val[root]>=x) ///根节点所在的值不选用 117 printf("%d\n",siz[son[root][0]]+1-1); ///最小的点 118 else 119 printf("%d\n",siz[son[root][0]]+cnt[root]+1-1); ///最小的点 120 } 121 122 int pre(int x) 123 { 124 find(x); 125 if (val[root]<x) 126 return root; 127 int cur=son[root][0]; 128 while (son[cur][1]) 129 cur=son[cur][1]; 130 splay(cur); 131 return cur; 132 } 133 134 int succ(int x) 135 { 136 find(x); 137 if (val[root]>x) 138 return root; 139 int cur=son[root][1]; 140 while (son[cur][0]) 141 cur=son[cur][0]; 142 splay(cur); 143 return cur; 144 } 145 146 void remove(int x) 147 { 148 int last=pre(x); 149 int next=succ(x); 150 splay(last); 151 splay(next,last); 152 int del=son[next][0]; ///有且只有一个节点 153 if (cnt[del]>1) 154 { 155 cnt[del]--; 156 splay(del); 157 } 158 else 159 son[next][0]=0; ///删除该节点 160 pushup(next),pushup(root); 161 } 162 163 int main() 164 { 165 int t,mode,x; 166 insert(0x3f3f3f3f); 167 insert(0xefefefef); 168 scanf("%d",&t); 169 while (t--) 170 { 171 scanf("%d%d",&mode,&x); 172 if (mode==1) 173 insert(x); 174 else if (mode==2) 175 remove(x); 176 else if (mode==3) 177 x_rank(x); 178 else if (mode==4) 179 printf("%d\n",val[kth(x+1)]); ///最小的点 180 else if (mode==5) 181 printf("%d\n",val[pre(x)]); 182 else if (mode==6) 183 printf("%d\n",val[succ(x)]); 184 } 185 return 0; 186 }
一些想法和其它的写法
1 #include2 #include 3 #include 4 #include 5 #include <string> 6 #include 7 #include 8 using namespace std; 9 #define ll long long 10 11 const double eps=1e-8; 12 const ll inf=1e9; 13 const ll mod=1e9+7; 14 const int maxn=1e5+10; 15 16 int par[maxn],son[maxn][2],siz[maxn],val[maxn],cnt[maxn],root,id; 17 18 int max_op; 19 20 int chk(int x) 21 { 22 return son[par[x]][1]==x; 23 } 24 25 void pushup(int x) 26 { 27 siz[x]=siz[son[x][0]]+siz[son[x][1]]+cnt[x]; 28 } 29 30 void rotate(int x) 31 { 32 int y=par[x]; 33 int z=par[y]; 34 int k=chk(x); 35 int w=son[x][k^1]; 36 son[y][k]=w,par[w]=y; 37 son[z][chk(y)]=x,par[x]=z; 38 son[x][k^1]=y,par[y]=x; 39 pushup(y),pushup(x); 40 } 41 42 void splay(int x,int goal=0) 43 { 44 int y,z; 45 while (par[x]!=goal) 46 { 47 y=par[x]; 48 z=par[y]; 49 if (z!=goal) 50 { 51 if (chk(x)==chk(y)) 52 rotate(y); 53 else 54 rotate(x); 55 } 56 rotate(x); 57 } 58 if (!goal) 59 root=x; 60 } 61 62 void find(int x) 63 { 64 if (!root) 65 return; 66 int cur=root; 67 while (son[cur][x>val[cur]] && x!=val[cur]) 68 cur=son[cur][x>val[cur]]; 69 splay(cur); ///用于找到排名,前继,后继 70 } 71 72 void insert(int x) 73 { 74 int cur=root,p=0; 75 while (cur && val[cur]!=x) 76 { 77 p=cur; 78 cur=son[cur][x>val[cur]]; 79 } 80 if (cur) 81 cnt[cur]++; 82 else 83 { 84 cur=++id; 85 if (p) 86 { 87 son[p][x>val[p]]=cur; 88 siz[p]++; ///不写也行,在splay(cur)中会更改 89 } 90 son[cur][0]=son[cur][1]=0; 91 val[cur]=x; 92 par[cur]=p; 93 cnt[cur]=siz[cur]=1; 94 } 95 splay(cur); ///保持平衡 96 } 97 98 int kth(int k) 99 { 100 int cur=root; 101 while (1) 102 { 103 if (son[cur][0] && k<=siz[son[cur][0]]) 104 cur=son[cur][0]; 105 else if (k>siz[son[cur][0]]+cnt[cur]) 106 { 107 k-=siz[son[cur][0]]+cnt[cur]; 108 cur=son[cur][1]; 109 } 110 else 111 return cur; 112 } 113 } 114 115 int x_rank(int x) 116 { 117 find(x); ///比x小的数目 +1 118 if (val[root]>=x) ///根节点所在的值不选用 119 return siz[son[root][0]]+1; ///最小的点 120 else 121 return siz[son[root][0]]+cnt[root]+1; ///最小的点 122 } 123 124 /** 125 超时 126 max_op=49999 127 128 下方的 129 1 1 130 1 2 131 1 3 132 ... 133 的读入方式,会使产生一条长长的链 134 135 136 求深度大的点, 137 splay操作, 138 会使深度趋于平衡。 139 140 在这里没有splay操作, 141 每次处理的都是长链 142 **/ 143 //int x_rank(int x) 144 //{ 145 // int op=0; 146 // int cur=root,sum=0; 147 // while (!(son[cur][0]==0 && son[cur][1]==0) && val[cur]!=x) 148 // { 149 // if (x 150 // cur=son[cur][0]; 151 // else 152 // { 153 // sum+=siz[son[cur][0]]+cnt[cur]; 154 // cur=son[cur][1]; 155 // } 156 // op++; 157 // } 158 // max_op=max(max_op,op); 159 // return sum+siz[son[cur][0]]+1; 160 //} 161 162 int pre(int x) 163 { 164 find(x); 165 if (val[root]<x) 166 return root; 167 int cur=son[root][0]; 168 while (son[cur][1]) 169 cur=son[cur][1]; 170 return cur; 171 } 172 173 ///also ok 174 //int pre(int x) 175 //{ 176 // int num=x_rank(x);///里面包含find函数 177 // return kth(num-1); 178 //} 179 180 int succ(int x) 181 { 182 find(x); 183 if (val[root]>x) 184 return root; 185 int cur=son[root][1]; 186 while (son[cur][0]) 187 cur=son[cur][0]; 188 return cur; 189 } 190 191 ///also ok 192 //int succ(int x) 193 //{ 194 // int num=x_rank(x); 195 // if (val[root]==x) 196 // return kth(num+cnt[root]); 197 // else 198 // return kth(num); 199 //} 200 201 void remove(int x) 202 { 203 int last=pre(x); 204 int next=succ(x); 205 splay(last); 206 splay(next,last); 207 int del=son[next][0]; ///有且只有一个节点 208 if (cnt[del]>1) 209 { 210 cnt[del]--; 211 splay(del); 212 } 213 else 214 son[next][0]=0; ///删除该节点 215 pushup(next),pushup(root); 216 } 217 218 int main() 219 { 220 int t,mode,x; 221 insert(0xefefefef); ///增加最小的点,pre也许不存在 222 insert(0x3f3f3f3f); ///增加最大的点,succ也许不存在 223 scanf("%d",&t); 224 while (t--) 225 { 226 scanf("%d%d",&mode,&x); 227 if (mode==1) 228 insert(x); 229 else if (mode==2) 230 remove(x); 231 else if (mode==3) 232 printf("%d\n",x_rank(x)-1); 233 else if (mode==4) 234 printf("%d\n",val[kth(x+1)]); ///最小的点 235 else if (mode==5) 236 printf("%d\n",val[pre(x)]); 237 else if (mode==6) 238 printf("%d\n",val[succ(x)]); 239 } 240 241 // printf("max_op=%d",max_op); 242 return 0; 243 } 244 /* 245 4 246 1 1 247 3 1 248 5 1 249 6 1 250 251 252 100 253 1 1 254 1 2 255 1 3 256 1 4 257 1 5 258 1 6 259 1 7 260 1 8 261 1 9 262 1 10 263 3 1 264 3 10 265 */
P3391 【模板】文艺平衡树(Splay)
1 #include2 #include 3 #include 4 #include 5 #include <string> 6 #include 7 #include 8 using namespace std; 9 #define ll long long 10 11 const double eps=1e-8; 12 const ll inf=1e9; 13 const ll mod=1e9+7; 14 const int maxn=1e5+10; 15 16 int vir1=0xefefefef,vir2=0x3f3f3f3f; 17 int par[maxn],son[maxn][2],val[maxn],siz[maxn],rev[maxn],id,root,n; 18 bool pr; 19 20 int chk(int x) 21 { 22 return son[par[x]][1]==x; 23 } 24 25 void pushup(int x) 26 { 27 siz[x]=siz[son[x][0]]+siz[son[x][1]]+1; 28 } 29 30 void rotate(int x) 31 { 32 int y=par[x]; 33 int z=par[y]; 34 int k=chk(x); 35 int w=son[x][k^1]; 36 son[y][k]=w,par[w]=y; 37 son[z][chk(y)]=x,par[x]=z; 38 son[x][k^1]=y,par[y]=x; 39 pushup(y),pushup(x); 40 } 41 42 void splay(int x,int goal=0) 43 { 44 int y,z; 45 while (par[x]!=goal) 46 { 47 y=par[x]; 48 z=par[y]; 49 if (z!=goal) 50 { 51 if (chk(x)==chk(y)) 52 rotate(y); 53 else 54 rotate(x); 55 } 56 rotate(x); 57 } 58 if (!goal) 59 root=x; 60 } 61 62 ///编号从小到大,当前编号比之前读入的数的编号大 63 void insert(int x) ///数值 64 { 65 int cur=root,p=0; 66 while (cur) 67 { 68 p=cur; 69 cur=son[cur][1]; 70 } 71 72 cur=++id; 73 if (p) 74 { 75 son[p][1]=cur; 76 siz[p]++; 77 } 78 son[cur][0]=son[cur][1]=0; 79 par[cur]=p; 80 val[cur]=x; 81 siz[cur]=1; 82 splay(cur); 83 } 84 85 void pushdown(int x) 86 { 87 if (rev[x]) 88 { 89 swap(son[x][0],son[x][1]); 90 rev[son[x][0]]^=1; 91 rev[son[x][1]]^=1; 92 rev[x]=0; 93 } 94 } 95 96 int kth(int k) 97 { 98 int cur=root; 99 while (1) 100 { 101 pushdown(cur); 102 if (son[cur][0] && k<=siz[son[cur][0]]) 103 cur=son[cur][0]; 104 else if (k>siz[son[cur][0]]+1) 105 { 106 k-=siz[son[cur][0]]+1; 107 cur=son[cur][1]; 108 } 109 else 110 return cur; 111 } 112 } 113 114 void reverse(int l,int r) 115 { 116 int x=kth(l-1),y=kth(r+1); 117 splay(x); 118 splay(y,x); 119 rev[son[y][0]]^=1; ///interval [l,r], between l-1 and r+1 120 } 121 122 void print(int x) 123 { 124 pushdown(x); 125 if (son[x][0]) 126 print(son[x][0]); 127 if (x!=1 && x!=n+2) ///smallest and largest number 128 { 129 if (!pr) 130 pr=1; 131 else 132 printf(" "); 133 printf("%d",val[x]); 134 } 135 if (son[x][1]) 136 print(son[x][1]); 137 } 138 139 int main() 140 { 141 int t,i,x,y; 142 scanf("%d%d",&n,&t); 143 insert(vir1); ///smallest number, for l-1 144 for (i=1;i<=n;i++) 145 insert(i); 146 insert(vir2); ///largest number, for r+1 147 while (t--) 148 { 149 scanf("%d%d",&x,&y); 150 reverse(x+1,y+1); ///contain virtual smallest number 151 } 152 print(root); 153 return 0; 154 } 155 /* 156 5 0 157 158 5 1 159 1 5 160 */
P2042 [NOI2005]维护数列
见 https://tiger0132.blog.luogu.org/slay-notes
P3380 【模板】二逼平衡树(树套树)
线段树套Splay
每个线段树的点区间有一个Splay。
每个点(a[1]~a[n])在log(n)个线段树的点区间中。
动态开点。
相比动态主席树的优势:
空间nlogn
时间复杂度:
参见https://www.cnblogs.com/LadyLex/p/8006478.html,讲得挺好
(图片来自https://www.cnblogs.com/LadyLex/p/8006478.html)
(图片来自https://www.luogu.org/problemnew/solution/P3380)
既然是区间第k大的时间复杂度是
log(n)*log(n)*log(value_range),
那么肯定会超时才对啊……
只有其它方法才能过……
或者是实际跑起来,远没有到达理论的时间复杂度……
估计是数据没有造到极限,
而我的代码常数太高了……
原来开O2优化(提交时选择)……
需要添加
#pragma GCC optimize(2)
调试时去掉这句话
否则有些变量显示optimized out,无法看到数值
也许更快的方法:
zkw线段树,树状数组
90分
求kth,记录修改的位置,之后不用每次求修改的位置(都是一样的)
1 #pragma GCC optimize(2) 2 #include3 #include 4 #include 5 #include 6 #include <string> 7 #include 8 #include 9 using namespace std; 10 #define ll long long 11 12 /** 13 log(n)=16 14 n*log(n)*log(n)=12800000 15 **/ 16 17 const double eps=1e-8; 18 const ll mod=1e9+7; 19 const int maxn=5e4+10; 20 const int maxf=maxn<<2; 21 const int maxg=maxn*18+maxf*2; 22 ///n * log(n)[larger] (每个点在log(n)个区间中出现) + 每个区间加上两个虚拟点(最小、最大) 23 24 struct node 25 { 26 int l,r,b; 27 }f[maxf]; 28 29 int par[maxg],son[maxg][2],val[maxg],cnt[maxg],siz[maxg]; 30 int a[maxn],id; 31 int minv=0,maxv=1e8,vir1=-2147483647,vir2=2147483647; 32 int cal_num[maxn],cnt_cal_num; 33 34 int chk(int x) 35 { 36 return son[par[x]][1]==x; 37 } 38 39 void pushup(int x) 40 { 41 siz[x]=siz[son[x][0]]+siz[son[x][1]]+cnt[x]; 42 } 43 44 void rotate(int x) 45 { 46 int y=par[x]; 47 int z=par[y]; 48 int k=chk(x); 49 int w=son[x][k^1]; 50 son[y][k]=w,par[w]=y; 51 son[z][chk(y)]=x,par[x]=z; 52 son[x][k^1]=y,par[y]=x; 53 pushup(y),pushup(x); 54 } 55 56 void splay(int &root,int x,int goal=0) 57 { 58 int y,z; 59 while (par[x]!=goal) 60 { 61 y=par[x]; 62 z=par[y]; 63 if (z!=goal) 64 { 65 if (chk(x)==chk(y)) 66 rotate(y); 67 else 68 rotate(x); 69 } 70 rotate(x); 71 } 72 if (!goal) 73 root=x; 74 } 75 76 void find(int &root,int x) 77 { 78 if (!root) 79 return; 80 int cur=root; 81 while (son[cur][x>val[cur]] && x!=val[cur]) 82 cur=son[cur][x>val[cur]]; 83 splay(root,cur); 84 } 85 86 int pre(int &root,int x) 87 { 88 find(root,x); 89 if (val[root]<x) 90 return root; 91 int cur=son[root][0]; 92 while (son[cur][1]) 93 cur=son[cur][1]; 94 return cur; 95 } 96 97 int succ(int &root,int x) 98 { 99 find(root,x); 100 if (val[root]>x) 101 return root; 102 int cur=son[root][1]; 103 while (son[cur][0]) 104 cur=son[cur][0]; 105 return cur; 106 } 107 108 void insert(int &root,int x) 109 { 110 int cur=root,p=0; 111 while (cur && val[cur]!=x) 112 { 113 p=cur; 114 cur=son[cur][x>val[cur]]; 115 } 116 if (cur) 117 cnt[cur]++; 118 else 119 { 120 cur=++id; 121 if (p) 122 { 123 son[p][x>val[p]]=cur; 124 siz[p]++; 125 } 126 son[cur][0]=son[cur][1]=0; 127 val[cur]=x; 128 par[cur]=p; 129 cnt[cur]=siz[cur]=1; 130 } 131 splay(root,cur); 132 } 133 134 void remove(int &root,int x) 135 { 136 int last=pre(root,x); 137 int next=succ(root,x); 138 splay(root,last); 139 splay(root,next,last); 140 int del=son[next][0]; 141 if (cnt[del]>1) 142 { 143 cnt[del]--; 144 splay(root,del); 145 } 146 else 147 son[next][0]=0; 148 pushup(next),pushup(root); 149 } 150 151 //int kth(int &root,int k) 152 //{ 153 // int cur=root; 154 // while (1) 155 // { 156 // if (son[cur][0] && k<=siz[son[cur][0]]) 157 // cur=son[cur][0]; 158 // else if (k>siz[son[cur][0]]+cnt[cur]) 159 // { 160 // k-=siz[son[cur][0]]+cnt[cur]; 161 // cur=son[cur][1]; 162 // } 163 // else 164 // return cur; 165 // } 166 //} 167 168 int x_rank(int &root,int x) 169 { 170 find(root,x); 171 if (val[root]>=x) 172 return siz[son[root][0]]; 173 else 174 return siz[son[root][0]]+cnt[root]; 175 } 176 177 void seg_insert(int ind,int l,int r,int x,int y) 178 { 179 ///也可以build()函数,初始化 180 if (!f[ind].b) 181 { 182 insert(f[ind].b,vir1); ///根节点编号为0 183 f[ind].b=id; ///根节点编号为id 184 insert(f[ind].b,vir2); 185 } 186 insert(f[ind].b,y); 187 if (l==r) 188 return; 189 int m=(l+r)>>1; 190 if (x<=m) 191 seg_insert(ind<<1,l,m,x,y); 192 else 193 seg_insert(ind<<1|1,m+1,r,x,y); 194 } 195 196 void seg_remove(int ind,int l,int r,int x,int y) 197 { 198 remove(f[ind].b,y); 199 if (l==r) 200 return; 201 int m=(l+r)>>1; 202 if (x<=m) 203 seg_remove(ind<<1,l,m,x,y); 204 else 205 seg_remove(ind<<1|1,m+1,r,x,y); 206 } 207 208 void cal_query_rank(int ind,int l,int r,int x,int y) 209 { 210 if (x<=l && r<=y) 211 { 212 cal_num[++cnt_cal_num]=ind; 213 return; 214 } 215 int m=(l+r)>>1; 216 if (x<=m) 217 cal_query_rank(ind<<1,l,m,x,y); 218 if (m<y) 219 cal_query_rank(ind<<1|1,m+1,r,x,y); 220 } 221 222 int query_rank(int ind,int l,int r,int x,int y,int z) 223 { 224 if (x<=l && r<=y) 225 return x_rank(f[ind].b,z)-1; ///减去最小虚拟点 226 227 int m=(l+r)>>1,sum=0; 228 if (x<=m) 229 sum+=query_rank(ind<<1,l,m,x,y,z); 230 if (m<y) 231 sum+=query_rank(ind<<1|1,m+1,r,x,y,z); 232 return sum; 233 } 234 235 int query_pre(int ind,int l,int r,int x,int y,int z) 236 { 237 if (x<=l && r<=y) 238 return val[pre(f[ind].b,z)]; 239 int m=(l+r)>>1,re=vir1; 240 if (x<=m) 241 re=max(re,query_pre(ind<<1,l,m,x,y,z)); 242 if (m<y) 243 re=max(re,query_pre(ind<<1|1,m+1,r,x,y,z)); 244 return re; 245 } 246 247 int query_succ(int ind,int l,int r,int x,int y,int z) 248 { 249 if (x<=l && r<=y) 250 return val[succ(f[ind].b,z)]; 251 int m=(l+r)>>1,re=vir2; 252 if (x<=m) 253 re=min(re,query_succ(ind<<1,l,m,x,y,z)); 254 if (m<y) 255 re=min(re,query_succ(ind<<1|1,m+1,r,x,y,z)); 256 return re; 257 } 258 259 int main() 260 { 261 int n,m,i,l,r,k,mode,x,L,R,mid; 262 scanf("%d%d",&n,&m); 263 for (i=1;i<=n;i++) 264 { 265 scanf("%d",&x); 266 seg_insert(1,1,n,i,x); 267 a[i]=x; 268 } 269 for (int M=1;M<=m;M++) 270 { 271 scanf("%d",&mode); 272 if (mode==3) 273 scanf("%d%d",&l,&k); 274 else 275 scanf("%d%d%d",&l,&r,&k); 276 if (mode==1) 277 ///log(n)*log(n) 278 printf("%d\n",query_rank(1,1,n,l,r,k)+1); ///比其小的点的数目+1 279 else if (mode==2) 280 { 281 ///log(value_range[maxv-minv]) 282 ///可离散化成log(maxn+maxm),但写起来很复杂 283 ///可记录区间的最小、最大值,但写起来很麻烦,特别是涉及了数字修改 284 285 ///每次遍历的内容都是一致的,用cal_query_rank函数记录下来 286 287 cnt_cal_num=0; 288 cal_query_rank(1,1,n,l,r); 289 290 L=minv,R=maxv; 291 while (L<=R) 292 { 293 mid=(L+R)>>1; 294 295 x=1; 296 for (i=1;i<=cnt_cal_num;i++) 297 x+=x_rank(f[cal_num[i]].b,mid)-1; ///f[index].b 会变化 298 299 ///log(n)*log(n) 300 // x=query_rank(1,1,n,l,r,mid)+1; /// 301 if (x<=k) 302 L=mid+1; 303 else 304 R=mid-1; 305 } 306 printf("%d\n",R); 307 } 308 else if (mode==3) 309 { 310 ///log(n)*log(n) 311 seg_remove(1,1,n,l,a[l]); 312 ///log(n)*log(n) 313 seg_insert(1,1,n,l,k); 314 a[l]=k; 315 } 316 else if (mode==4) 317 ///log(n)*log(n) 318 printf("%d\n",query_pre(1,1,n,l,r,k)); 319 else 320 ///log(n)*log(n) 321 printf("%d\n",query_succ(1,1,n,l,r,k)); 322 } 323 return 0; 324 } 325 /* 326 9 100 327 4 2 2 1 9 4 0 1 1 328 329 1 1 5 1 330 1 1 5 2 331 1 1 5 3 332 1 1 5 4 333 1 1 5 5 334 335 2 1 5 1 336 2 1 5 2 337 2 1 5 3 338 2 1 5 4 339 2 1 5 5 340 341 3 3 0 342 1 1 5 3 343 3 3 1 344 1 1 5 3 345 3 3 2 346 1 1 5 3 347 3 3 3 348 1 1 5 3 349 3 3 5 350 1 1 5 3 351 3 3 10 352 1 1 5 3 353 3 3 2 354 355 4 1 5 0 356 4 1 5 1 357 4 1 5 2 358 4 1 5 3 359 4 1 5 4 360 4 1 5 5 361 362 5 1 5 0 363 5 1 5 1 364 5 1 5 2 365 5 1 5 3 366 5 1 5 4 367 5 1 5 9 368 5 1 5 10 369 370 371 9 100 372 1 1 1 1 1 1 1 1 1 373 1 1 10 1 374 1 1 10 10 375 1 1 10 5 376 2 1 10 1 377 2 1 10 9 378 2 1 10 5 379 4 1 10 1 380 4 1 10 5 381 5 1 10 1 382 5 1 10 -5 383 384 385 5 100 386 1 2 3 2 1 387 2 1 5 1 388 2 1 5 2 389 2 1 5 3 390 2 1 5 4 391 2 1 5 5 392 2 2 5 1 393 2 2 5 2 394 2 2 5 3 395 2 2 5 4 396 2 3 4 1 397 2 3 4 2 398 399 1 400 */
求kth
二分答案,original r-l = 1e8
离散化
1e8->5e4+5e4
次数 log(1e8)->log(5e4+5e4)
反而是80分,估计是排序操作消耗了一段时间
1 #pragma GCC optimize(2) 2 #include3 #include 4 #include 5 #include 6 #include <string> 7 #include 8 #include 9 using namespace std; 10 #define ll long long 11 12 /** 13 log(n)=16 14 n*log(n)*log(n)=12800000 15 **/ 16 17 const double eps=1e-8; 18 const ll mod=1e9+7; 19 const int maxn=5e4+10; 20 const int maxm=5e4+10; 21 const int maxf=maxn<<2; 22 const int maxg=maxn*18+maxf*2; 23 ///n * log(n)[larger] (每个点在log(n)个区间中出现) + 每个区间加上两个虚拟点(最小、最大) 24 25 int in_n[maxn],in_m[maxm][4],new_vir1,new_vir2; 26 27 struct rec 28 { 29 int v,num; 30 bool operator<(const rec &y) const 31 { 32 return v<y.v; 33 } 34 }value[maxn+maxm]; 35 int cnt_value,id_value,value_rev[maxn+maxm]; 36 37 struct node 38 { 39 int l,r,b; 40 }f[maxf]; 41 42 int par[maxg],son[maxg][2],val[maxg],cnt[maxg],siz[maxg]; 43 int a[maxn],id; 44 int minv=0,maxv=1e8,vir1=-2147483647,vir2=2147483647; 45 int cal_num[maxn],cnt_cal_num; 46 47 int chk(int x) 48 { 49 return son[par[x]][1]==x; 50 } 51 52 void pushup(int x) 53 { 54 siz[x]=siz[son[x][0]]+siz[son[x][1]]+cnt[x]; 55 } 56 57 void rotate(int x) 58 { 59 int y=par[x]; 60 int z=par[y]; 61 int k=chk(x); 62 int w=son[x][k^1]; 63 son[y][k]=w,par[w]=y; 64 son[z][chk(y)]=x,par[x]=z; 65 son[x][k^1]=y,par[y]=x; 66 pushup(y),pushup(x); 67 } 68 69 void splay(int &root,int x,int goal=0) 70 { 71 int y,z; 72 while (par[x]!=goal) 73 { 74 y=par[x]; 75 z=par[y]; 76 if (z!=goal) 77 { 78 if (chk(x)==chk(y)) 79 rotate(y); 80 else 81 rotate(x); 82 } 83 rotate(x); 84 } 85 if (!goal) 86 root=x; 87 } 88 89 void find(int &root,int x) 90 { 91 if (!root) 92 return; 93 int cur=root; 94 while (son[cur][x>val[cur]] && x!=val[cur]) 95 cur=son[cur][x>val[cur]]; 96 splay(root,cur); 97 } 98 99 int pre(int &root,int x) 100 { 101 find(root,x); 102 if (val[root]<x) 103 return root; 104 int cur=son[root][0]; 105 while (son[cur][1]) 106 cur=son[cur][1]; 107 return cur; 108 } 109 110 int succ(int &root,int x) 111 { 112 find(root,x); 113 if (val[root]>x) 114 return root; 115 int cur=son[root][1]; 116 while (son[cur][0]) 117 cur=son[cur][0]; 118 return cur; 119 } 120 121 void insert(int &root,int x) 122 { 123 int cur=root,p=0; 124 while (cur && val[cur]!=x) 125 { 126 p=cur; 127 cur=son[cur][x>val[cur]]; 128 } 129 if (cur) 130 cnt[cur]++; 131 else 132 { 133 cur=++id; 134 if (p) 135 { 136 son[p][x>val[p]]=cur; 137 siz[p]++; 138 } 139 son[cur][0]=son[cur][1]=0; 140 val[cur]=x; 141 par[cur]=p; 142 cnt[cur]=siz[cur]=1; 143 } 144 splay(root,cur); 145 } 146 147 void remove(int &root,int x) 148 { 149 int last=pre(root,x); 150 int next=succ(root,x); 151 splay(root,last); 152 splay(root,next,last); 153 int del=son[next][0]; 154 if (cnt[del]>1) 155 { 156 cnt[del]--; 157 splay(root,del); 158 } 159 else 160 son[next][0]=0; 161 pushup(next),pushup(root); 162 } 163 164 //int kth(int &root,int k) 165 //{ 166 // int cur=root; 167 // while (1) 168 // { 169 // if (son[cur][0] && k<=siz[son[cur][0]]) 170 // cur=son[cur][0]; 171 // else if (k>siz[son[cur][0]]+cnt[cur]) 172 // { 173 // k-=siz[son[cur][0]]+cnt[cur]; 174 // cur=son[cur][1]; 175 // } 176 // else 177 // return cur; 178 // } 179 //} 180 181 int x_rank(int &root,int x) 182 { 183 find(root,x); 184 if (val[root]>=x) 185 return siz[son[root][0]]; 186 else 187 return siz[son[root][0]]+cnt[root]; 188 } 189 190 void seg_insert(int ind,int l,int r,int x,int y) 191 { 192 ///也可以build()函数,初始化 193 if (!f[ind].b) 194 { 195 insert(f[ind].b,new_vir1); ///根节点编号为0,vir1 196 f[ind].b=id; ///根节点编号为id 197 insert(f[ind].b,new_vir2); ///vir2 198 } 199 insert(f[ind].b,y); 200 if (l==r) 201 return; 202 int m=(l+r)>>1; 203 if (x<=m) 204 seg_insert(ind<<1,l,m,x,y); 205 else 206 seg_insert(ind<<1|1,m+1,r,x,y); 207 } 208 209 void seg_remove(int ind,int l,int r,int x,int y) 210 { 211 remove(f[ind].b,y); 212 if (l==r) 213 return; 214 int m=(l+r)>>1; 215 if (x<=m) 216 seg_remove(ind<<1,l,m,x,y); 217 else 218 seg_remove(ind<<1|1,m+1,r,x,y); 219 } 220 221 void cal_query_rank(int ind,int l,int r,int x,int y) 222 { 223 if (x<=l && r<=y) 224 { 225 cal_num[++cnt_cal_num]=ind; 226 return; 227 } 228 int m=(l+r)>>1; 229 if (x<=m) 230 cal_query_rank(ind<<1,l,m,x,y); 231 if (m<y) 232 cal_query_rank(ind<<1|1,m+1,r,x,y); 233 } 234 235 int query_rank(int ind,int l,int r,int x,int y,int z) 236 { 237 if (x<=l && r<=y) 238 return x_rank(f[ind].b,z)-1; ///减去最小虚拟点 239 240 int m=(l+r)>>1,sum=0; 241 if (x<=m) 242 sum+=query_rank(ind<<1,l,m,x,y,z); 243 if (m<y) 244 sum+=query_rank(ind<<1|1,m+1,r,x,y,z); 245 return sum; 246 } 247 248 int query_pre(int ind,int l,int r,int x,int y,int z) 249 { 250 if (x<=l && r<=y) 251 return val[pre(f[ind].b,z)]; 252 int m=(l+r)>>1,re=new_vir1;///vir1 253 if (x<=m) 254 re=max(re,query_pre(ind<<1,l,m,x,y,z)); 255 if (m<y) 256 re=max(re,query_pre(ind<<1|1,m+1,r,x,y,z)); 257 return re; 258 } 259 260 int query_succ(int ind,int l,int r,int x,int y,int z) 261 { 262 if (x<=l && r<=y) 263 return val[succ(f[ind].b,z)]; 264 int m=(l+r)>>1,re=new_vir2;///vir2 265 if (x<=m) 266 re=min(re,query_succ(ind<<1,l,m,x,y,z)); 267 if (m<y) 268 re=min(re,query_succ(ind<<1|1,m+1,r,x,y,z)); 269 return re; 270 } 271 272 int main() 273 { 274 int n,m,i,l,r,k,mode,x,L,R,mid; 275 scanf("%d%d",&n,&m); 276 277 for (i=1;i<=n;i++) 278 { 279 scanf("%d",&in_n[i]); 280 value[++cnt_value]={in_n[i],i}; 281 } 282 for (i=1;i<=m;i++) 283 { 284 scanf("%d",&in_m[i][0]); 285 if (in_m[i][0]==3) 286 { 287 scanf("%d%d",&in_m[i][1],&in_m[i][2]); 288 value[++cnt_value]={in_m[i][2],n+i}; 289 } 290 else 291 { 292 scanf("%d%d%d",&in_m[i][1],&in_m[i][3],&in_m[i][2]); 293 if (in_m[i][0]!=2) 294 value[++cnt_value]={in_m[i][2],n+i}; 295 } 296 } 297 value[++cnt_value]={vir1,0}; 298 value[++cnt_value]={vir2,0}; 299 300 sort(value+1,value+cnt_value+1); 301 value[0].v=value[1].v-1; 302 for (i=1;i<=cnt_value;i++) 303 { 304 if (value[i].v!=value[i-1].v) 305 value_rev[++id_value]=value[i].v; 306 307 if (value[i].v==vir1 || value[i].v==vir2) 308 continue; 309 310 if (value[i].num<=n) 311 in_n[value[i].num]=id_value; 312 else 313 in_m[value[i].num-n][2]=id_value; 314 } 315 new_vir1=1; 316 new_vir2=id_value; 317 318 for (i=1;i<=n;i++) 319 { 320 // scanf("%d",&x); 321 x=in_n[i]; 322 seg_insert(1,1,n,i,x); 323 a[i]=x; 324 } 325 326 for (int M=1;M<=m;M++) 327 { 328 mode=in_m[M][0]; 329 // scanf("%d",&mode); 330 if (mode==3) 331 l=in_m[M][1],k=in_m[M][2]; 332 // scanf("%d%d",&l,&k); 333 else 334 l=in_m[M][1],r=in_m[M][3],k=in_m[M][2]; ///attention! 335 336 // scanf("%d%d%d",&l,&r,&k); 337 if (mode==1) 338 ///log(n)*log(n) 339 printf("%d\n",query_rank(1,1,n,l,r,k)+1); ///比其小的点的数目+1 340 else if (mode==2) 341 { 342 ///log(value_range[maxv-minv]) 343 ///可离散化成log(maxn+maxm),但写起来很复杂 344 ///可记录区间的最小、最大值,但写起来很麻烦,特别是涉及了数字修改 345 346 ///每次遍历的内容都是一致的,用cal_query_rank函数记录下来 347 348 cnt_cal_num=0; 349 cal_query_rank(1,1,n,l,r); 350 351 L=minv,R=maxv; 352 while (L<=R) 353 { 354 mid=(L+R)>>1; 355 356 x=1; 357 for (i=1;i<=cnt_cal_num;i++) 358 x+=x_rank(f[cal_num[i]].b,mid)-1; ///f[index].b 会变化 359 360 ///log(n)*log(n) 361 // x=query_rank(1,1,n,l,r,mid)+1; /// 362 if (x<=k) 363 L=mid+1; 364 else 365 R=mid-1; 366 } 367 printf("%d\n",value_rev[R]); /// 368 } 369 else if (mode==3) 370 { 371 ///log(n)*log(n) 372 seg_remove(1,1,n,l,a[l]); 373 ///log(n)*log(n) 374 seg_insert(1,1,n,l,k); 375 a[l]=k; 376 } 377 else if (mode==4) 378 ///log(n)*log(n) 379 printf("%d\n",value_rev[query_pre(1,1,n,l,r,k)]); 380 else 381 ///log(n)*log(n) 382 printf("%d\n",value_rev[query_succ(1,1,n,l,r,k)]); 383 } 384 return 0; 385 } 386 /* 387 9 36 388 4 2 2 1 9 4 0 1 1 389 390 1 1 5 1 391 1 1 5 2 392 1 1 5 3 393 1 1 5 4 394 1 1 5 5 395 396 2 1 5 1 397 2 1 5 2 398 2 1 5 3 399 2 1 5 4 400 2 1 5 5 401 402 3 3 0 403 1 1 5 3 404 3 3 1 405 1 1 5 3 406 3 3 2 407 1 1 5 3 408 3 3 3 409 1 1 5 3 410 3 3 5 411 1 1 5 3 412 3 3 10 413 1 1 5 3 414 3 3 2 415 416 4 1 5 0 417 4 1 5 1 418 4 1 5 2 419 4 1 5 3 420 4 1 5 4 421 4 1 5 5 422 423 5 1 5 0 424 5 1 5 1 425 5 1 5 2 426 5 1 5 3 427 5 1 5 4 428 5 1 5 9 429 5 1 5 10 430 431 432 9 100 433 1 1 1 1 1 1 1 1 1 434 1 1 10 1 435 1 1 10 10 436 1 1 10 5 437 2 1 10 1 438 2 1 10 9 439 2 1 10 5 440 4 1 10 1 441 4 1 10 5 442 5 1 10 1 443 5 1 10 -5 444 445 446 5 100 447 1 2 3 2 1 448 2 1 5 1 449 2 1 5 2 450 2 1 5 3 451 2 1 5 4 452 2 1 5 5 453 2 2 5 1 454 2 2 5 2 455 2 2 5 3 456 2 2 5 4 457 2 3 4 1 458 2 3 4 2 459 460 1 4 461 1 462 5 1 1 -1 463 5 1 1 10 464 6 1 1 -1 465 6 1 1 10 466 467 9 1 468 4 2 2 1 9 4 0 1 1 469 5 1 5 10 470 */
从上到下
第二个:加splay(),考虑'到刚访问的节点在之后有可能很快将再次访问'
第一个:root形参->全局变量+指针(用于修改)
第三个:
1 #include2 #include 3 #include 4 #include 5 #include <string> 6 #include 7 #include 8 using namespace std; 9 #define ll long long 10 11 /** 12 log(n)=16 13 n*log(n)*log(n)=12800000 14 **/ 15 16 const double eps=1e-8; 17 const ll mod=1e9+7; 18 const int maxn=5e4+10; 19 const int maxf=maxn<<2; 20 const int maxg=maxn*18+maxf*2; 21 ///n * log(n)[larger] (每个点在log(n)个区间中出现) + 每个区间加上两个虚拟点(最小、最大) 22 23 struct node 24 { 25 int l,r,b; 26 }f[maxf]; 27 28 int par[maxg],son[maxg][2],val[maxg],cnt[maxg],siz[maxg]; 29 int a[maxn],id; 30 int minv=0,maxv=1e8,vir1=-2147483647,vir2=2147483647; 31 32 int chk(int x) 33 { 34 return son[par[x]][1]==x; 35 } 36 37 void pushup(int x) 38 { 39 siz[x]=siz[son[x][0]]+siz[son[x][1]]+cnt[x]; 40 } 41 42 void rotate(int x) 43 { 44 int y=par[x]; 45 int z=par[y]; 46 int k=chk(x); 47 int w=son[x][k^1]; 48 son[y][k]=w,par[w]=y; 49 son[z][chk(y)]=x,par[x]=z; 50 son[x][k^1]=y,par[y]=x; 51 pushup(y),pushup(x); 52 } 53 54 void splay(int &root,int x,int goal=0) 55 { 56 int y,z; 57 while (par[x]!=goal) 58 { 59 y=par[x]; 60 z=par[y]; 61 if (z!=goal) 62 { 63 if (chk(x)==chk(y)) 64 rotate(y); 65 else 66 rotate(x); 67 } 68 rotate(x); 69 } 70 if (!goal) 71 root=x; 72 } 73 74 void find(int &root,int x) 75 { 76 if (!root) 77 return; 78 int cur=root; 79 while (son[cur][x>val[cur]] && x!=val[cur]) 80 cur=son[cur][x>val[cur]]; 81 splay(root,cur); 82 } 83 84 int pre(int &root,int x) 85 { 86 find(root,x); 87 if (val[root]<x) 88 return root; 89 int cur=son[root][0]; 90 while (son[cur][1]) 91 cur=son[cur][1]; 92 return cur; 93 } 94 95 int succ(int &root,int x) 96 { 97 find(root,x); 98 if (val[root]>x) 99 return root; 100 int cur=son[root][1]; 101 while (son[cur][0]) 102 cur=son[cur][0]; 103 return cur; 104 } 105 106 void insert(int &root,int x) 107 { 108 int cur=root,p=0; 109 while (cur && val[cur]!=x) 110 { 111 p=cur; 112 cur=son[cur][x>val[cur]]; 113 } 114 if (cur) 115 cnt[cur]++; 116 else 117 { 118 cur=++id; 119 if (p) 120 { 121 son[p][x>val[p]]=cur; 122 siz[p]++; 123 } 124 son[cur][0]=son[cur][1]=0; 125 val[cur]=x; 126 par[cur]=p; 127 cnt[cur]=siz[cur]=1; 128 } 129 splay(root,cur); 130 } 131 132 void remove(int &root,int x) 133 { 134 int last=pre(root,x); 135 int next=succ(root,x); 136 splay(root,last); 137 splay(root,next,last); 138 int del=son[next][0]; 139 if (cnt[del]>1) 140 { 141 cnt[del]--; 142 splay(root,del); 143 } 144 else 145 son[next][0]=0; 146 pushup(next),pushup(root); 147 } 148 149 //int kth(int &root,int k) 150 //{ 151 // int cur=root; 152 // while (1) 153 // { 154 // if (son[cur][0] && k<=siz[son[cur][0]]) 155 // cur=son[cur][0]; 156 // else if (k>siz[son[cur][0]]+cnt[cur]) 157 // { 158 // k-=siz[son[cur][0]]+cnt[cur]; 159 // cur=son[cur][1]; 160 // } 161 // else 162 // return cur; 163 // } 164 //} 165 166 int x_rank(int &root,int x) 167 { 168 find(root,x); 169 if (val[root]>=x) 170 return siz[son[root][0]]; 171 else 172 return siz[son[root][0]]+cnt[root]; 173 } 174 175 void seg_insert(int ind,int l,int r,int x,int y) 176 { 177 ///也可以build()函数,初始化 178 if (!f[ind].b) 179 { 180 insert(f[ind].b,vir1); ///根节点编号为0 181 f[ind].b=id; ///根节点编号为id 182 insert(f[ind].b,vir2); 183 } 184 insert(f[ind].b,y); 185 if (l==r) 186 return; 187 int m=(l+r)>>1; 188 if (x<=m) 189 seg_insert(ind<<1,l,m,x,y); 190 else 191 seg_insert(ind<<1|1,m+1,r,x,y); 192 } 193 194 void seg_remove(int ind,int l,int r,int x,int y) 195 { 196 remove(f[ind].b,y); 197 if (l==r) 198 return; 199 int m=(l+r)>>1; 200 if (x<=m) 201 seg_remove(ind<<1,l,m,x,y); 202 else 203 seg_remove(ind<<1|1,m+1,r,x,y); 204 } 205 206 int query_rank(int ind,int l,int r,int x,int y,int z) 207 { 208 if (x<=l && r<=y) 209 return x_rank(f[ind].b,z)-1; ///减去最小虚拟点 210 int m=(l+r)>>1,sum=0; 211 if (x<=m) 212 sum+=query_rank(ind<<1,l,m,x,y,z); 213 if (m<y) 214 sum+=query_rank(ind<<1|1,m+1,r,x,y,z); 215 return sum; 216 } 217 218 int query_pre(int ind,int l,int r,int x,int y,int z) 219 { 220 if (x<=l && r<=y) 221 return val[pre(f[ind].b,z)]; 222 int m=(l+r)>>1,re=vir1; 223 if (x<=m) 224 re=max(re,query_pre(ind<<1,l,m,x,y,z)); 225 if (m<y) 226 re=max(re,query_pre(ind<<1|1,m+1,r,x,y,z)); 227 return re; 228 } 229 230 int query_succ(int ind,int l,int r,int x,int y,int z) 231 { 232 if (x<=l && r<=y) 233 return val[succ(f[ind].b,z)]; 234 int m=(l+r)>>1,re=vir2; 235 if (x<=m) 236 re=min(re,query_succ(ind<<1,l,m,x,y,z)); 237 if (m<y) 238 re=min(re,query_succ(ind<<1|1,m+1,r,x,y,z)); 239 return re; 240 } 241 242 int main() 243 { 244 int n,m,i,l,r,k,mode,x,L,R,mid; 245 scanf("%d%d",&n,&m); 246 for (i=1;i<=n;i++) 247 { 248 scanf("%d",&x); 249 seg_insert(1,1,n,i,x); 250 a[i]=x; 251 } 252 while (m--) 253 { 254 scanf("%d",&mode); 255 if (mode==3) 256 scanf("%d%d",&l,&k); 257 else 258 scanf("%d%d%d",&l,&r,&k); 259 if (mode==1) 260 ///log(n)*log(n) 261 printf("%d\n",query_rank(1,1,n,l,r,k)+1); ///比其小的点的数目+1 262 else if (mode==2) 263 { 264 ///log(value_range[maxv-minv]) 265 ///可离散化成log(maxn+maxm),但写起来很复杂 266 L=minv,R=maxv; 267 while (L<=R) 268 { 269 mid=(L+R)>>1; 270 ///log(n)*log(n) 271 x=query_rank(1,1,n,l,r,mid)+1; /// 272 if (x<=k) 273 L=mid+1; 274 else 275 R=mid-1; 276 } 277 printf("%d\n",R); 278 } 279 else if (mode==3) 280 { 281 ///log(n)*log(n) 282 seg_remove(1,1,n,l,a[l]); 283 ///log(n)*log(n) 284 seg_insert(1,1,n,l,k); 285 a[l]=k; 286 } 287 else if (mode==4) 288 ///log(n)*log(n) 289 printf("%d\n",query_pre(1,1,n,l,r,k)); 290 else 291 ///log(n)*log(n) 292 printf("%d\n",query_succ(1,1,n,l,r,k)); 293 } 294 return 0; 295 } 296 /* 297 9 100 298 4 2 2 1 9 4 0 1 1 299 300 1 1 5 1 301 1 1 5 2 302 1 1 5 3 303 1 1 5 4 304 1 1 5 5 305 306 2 1 5 1 307 2 1 5 2 308 2 1 5 3 309 2 1 5 4 310 2 1 5 5 311 312 3 3 0 313 1 1 5 3 314 3 3 1 315 1 1 5 3 316 3 3 2 317 1 1 5 3 318 3 3 3 319 1 1 5 3 320 3 3 5 321 1 1 5 3 322 3 3 10 323 1 1 5 3 324 3 3 2 325 326 4 1 5 0 327 4 1 5 1 328 4 1 5 2 329 4 1 5 3 330 4 1 5 4 331 4 1 5 5 332 333 5 1 5 0 334 5 1 5 1 335 5 1 5 2 336 5 1 5 3 337 5 1 5 4 338 5 1 5 9 339 5 1 5 10 340 341 9 100 342 1 1 1 1 1 1 1 1 1 343 1 1 10 1 344 1 1 10 10 345 1 1 10 5 346 2 1 10 1 347 2 1 10 9 348 2 1 10 5 349 4 1 10 1 350 4 1 10 5 351 5 1 10 1 352 5 1 10 -5 353 354 */
第二个:
1 /** 2 考虑到刚访问的节点在之后有可能很快将再次访问 3 **/ 4 #include5 #include 6 #include 7 #include 8 #include <string> 9 #include 10 #include 11 using namespace std; 12 #define ll long long 13 14 /** 15 log(n)=16 16 n*log(n)*log(n)=12800000 17 **/ 18 19 const double eps=1e-8; 20 const ll mod=1e9+7; 21 const int maxn=5e4+10; 22 const int maxf=maxn<<2; 23 const int maxg=maxn*18+maxf*2; 24 ///n * log(n)[larger] (每个点在log(n)个区间中出现) + 每个区间加上两个虚拟点(最小、最大) 25 26 struct node 27 { 28 int l,r,b; 29 }f[maxf]; 30 31 int par[maxg],son[maxg][2],val[maxg],cnt[maxg],siz[maxg]; 32 int a[maxn],id; 33 int minv=0,maxv=1e8,vir1=-2147483647,vir2=2147483647; 34 35 int chk(int x) 36 { 37 return son[par[x]][1]==x; 38 } 39 40 void pushup(int x) 41 { 42 siz[x]=siz[son[x][0]]+siz[son[x][1]]+cnt[x]; 43 } 44 45 void rotate(int x) 46 { 47 int y=par[x]; 48 int z=par[y]; 49 int k=chk(x); 50 int w=son[x][k^1]; 51 son[y][k]=w,par[w]=y; 52 son[z][chk(y)]=x,par[x]=z; 53 son[x][k^1]=y,par[y]=x; 54 pushup(y),pushup(x); 55 } 56 57 void splay(int &root,int x,int goal=0) 58 { 59 int y,z; 60 while (par[x]!=goal) 61 { 62 y=par[x]; 63 z=par[y]; 64 if (z!=goal) 65 { 66 if (chk(x)==chk(y)) 67 rotate(y); 68 else 69 rotate(x); 70 } 71 rotate(x); 72 } 73 if (!goal) 74 root=x; 75 } 76 77 void find(int &root,int x) 78 { 79 if (!root) 80 return; 81 int cur=root; 82 while (son[cur][x>val[cur]] && x!=val[cur]) 83 cur=son[cur][x>val[cur]]; 84 splay(root,cur); 85 } 86 87 int pre(int &root,int x) 88 { 89 find(root,x); 90 if (val[root]<x) 91 return root; 92 int cur=son[root][0]; 93 while (son[cur][1]) 94 cur=son[cur][1]; 95 splay(root,cur); 96 return cur; 97 } 98 99 int succ(int &root,int x) 100 { 101 find(root,x); 102 if (val[root]>x) 103 return root; 104 int cur=son[root][1]; 105 while (son[cur][0]) 106 cur=son[cur][0]; 107 splay(root,cur); 108 return cur; 109 } 110 111 void insert(int &root,int x) 112 { 113 int cur=root,p=0; 114 while (cur && val[cur]!=x) 115 { 116 p=cur; 117 cur=son[cur][x>val[cur]]; 118 } 119 if (cur) 120 cnt[cur]++; 121 else 122 { 123 cur=++id; 124 if (p) 125 { 126 son[p][x>val[p]]=cur; 127 siz[p]++; 128 } 129 son[cur][0]=son[cur][1]=0; 130 val[cur]=x; 131 par[cur]=p; 132 cnt[cur]=siz[cur]=1; 133 } 134 splay(root,cur); 135 } 136 137 void remove(int &root,int x) 138 { 139 int last=pre(root,x); 140 int next=succ(root,x); 141 splay(root,last); 142 splay(root,next,last); 143 int del=son[next][0]; 144 if (cnt[del]>1) 145 { 146 cnt[del]--; 147 splay(root,del); 148 } 149 else 150 son[next][0]=0; 151 pushup(next),pushup(root); 152 } 153 154 //int kth(int &root,int k) 155 //{ 156 // int cur=root; 157 // while (1) 158 // { 159 // if (son[cur][0] && k<=siz[son[cur][0]]) 160 // cur=son[cur][0]; 161 // else if (k>siz[son[cur][0]]+cnt[cur]) 162 // { 163 // k-=siz[son[cur][0]]+cnt[cur]; 164 // cur=son[cur][1]; 165 // } 166 // else 167 // { 168 // splay(cur); 169 // return cur; 170 // } 171 // } 172 //} 173 174 int x_rank(int &root,int x) 175 { 176 find(root,x); 177 if (val[root]>=x) 178 return siz[son[root][0]]; 179 else 180 return siz[son[root][0]]+cnt[root]; 181 } 182 183 void seg_insert(int ind,int l,int r,int x,int y) 184 { 185 ///也可以build()函数,初始化 186 if (!f[ind].b) 187 { 188 insert(f[ind].b,vir1); ///根节点编号为0 189 f[ind].b=id; ///根节点编号为id 190 insert(f[ind].b,vir2); 191 } 192 insert(f[ind].b,y); 193 if (l==r) 194 return; 195 int m=(l+r)>>1; 196 if (x<=m) 197 seg_insert(ind<<1,l,m,x,y); 198 else 199 seg_insert(ind<<1|1,m+1,r,x,y); 200 } 201 202 void seg_remove(int ind,int l,int r,int x,int y) 203 { 204 remove(f[ind].b,y); 205 if (l==r) 206 return; 207 int m=(l+r)>>1; 208 if (x<=m) 209 seg_remove(ind<<1,l,m,x,y); 210 else 211 seg_remove(ind<<1|1,m+1,r,x,y); 212 } 213 214 int query_rank(int ind,int l,int r,int x,int y,int z) 215 { 216 if (x<=l && r<=y) 217 return x_rank(f[ind].b,z)-1; ///减去最小虚拟点 218 int m=(l+r)>>1,sum=0; 219 if (x<=m) 220 sum+=query_rank(ind<<1,l,m,x,y,z); 221 if (m<y) 222 sum+=query_rank(ind<<1|1,m+1,r,x,y,z); 223 return sum; 224 } 225 226 int query_pre(int ind,int l,int r,int x,int y,int z) 227 { 228 if (x<=l && r<=y) 229 return val[pre(f[ind].b,z)]; 230 int m=(l+r)>>1,re=vir1; 231 if (x<=m) 232 re=max(re,query_pre(ind<<1,l,m,x,y,z)); 233 if (m<y) 234 re=max(re,query_pre(ind<<1|1,m+1,r,x,y,z)); 235 return re; 236 } 237 238 int query_succ(int ind,int l,int r,int x,int y,int z) 239 { 240 if (x<=l && r<=y) 241 return val[succ(f[ind].b,z)]; 242 int m=(l+r)>>1,re=vir2; 243 if (x<=m) 244 re=min(re,query_succ(ind<<1,l,m,x,y,z)); 245 if (m<y) 246 re=min(re,query_succ(ind<<1|1,m+1,r,x,y,z)); 247 return re; 248 } 249 250 int main() 251 { 252 int n,m,i,l,r,k,mode,x,L,R,mid; 253 scanf("%d%d",&n,&m); 254 for (i=1;i<=n;i++) 255 { 256 scanf("%d",&x); 257 seg_insert(1,1,n,i,x); 258 a[i]=x; 259 } 260 while (m--) 261 { 262 scanf("%d",&mode); 263 if (mode==3) 264 scanf("%d%d",&l,&k); 265 else 266 scanf("%d%d%d",&l,&r,&k); 267 if (mode==1) 268 ///log(n)*log(n) 269 printf("%d\n",query_rank(1,1,n,l,r,k)+1); ///比其小的点的数目+1 270 else if (mode==2) 271 { 272 ///log(value_range[maxv-minv]) 273 ///可离散化成log(maxn+maxm),但写起来很复杂 274 L=minv,R=maxv; 275 while (L<=R) 276 { 277 mid=(L+R)>>1; 278 ///log(n)*log(n) 279 x=query_rank(1,1,n,l,r,mid)+1; /// 280 if (x<=k) 281 L=mid+1; 282 else 283 R=mid-1; 284 } 285 printf("%d\n",R); 286 } 287 else if (mode==3) 288 { 289 ///log(n)*log(n) 290 seg_remove(1,1,n,l,a[l]); 291 ///log(n)*log(n) 292 seg_insert(1,1,n,l,k); 293 a[l]=k; 294 } 295 else if (mode==4) 296 ///log(n)*log(n) 297 printf("%d\n",query_pre(1,1,n,l,r,k)); 298 else 299 ///log(n)*log(n) 300 printf("%d\n",query_succ(1,1,n,l,r,k)); 301 } 302 return 0; 303 } 304 /* 305 9 100 306 4 2 2 1 9 4 0 1 1 307 308 1 1 5 1 309 1 1 5 2 310 1 1 5 3 311 1 1 5 4 312 1 1 5 5 313 314 2 1 5 1 315 2 1 5 2 316 2 1 5 3 317 2 1 5 4 318 2 1 5 5 319 320 3 3 0 321 1 1 5 3 322 3 3 1 323 1 1 5 3 324 3 3 2 325 1 1 5 3 326 3 3 3 327 1 1 5 3 328 3 3 5 329 1 1 5 3 330 3 3 10 331 1 1 5 3 332 3 3 2 333 334 4 1 5 0 335 4 1 5 1 336 4 1 5 2 337 4 1 5 3 338 4 1 5 4 339 4 1 5 5 340 341 5 1 5 0 342 5 1 5 1 343 5 1 5 2 344 5 1 5 3 345 5 1 5 4 346 5 1 5 9 347 5 1 5 10 348 349 9 100 350 1 1 1 1 1 1 1 1 1 351 1 1 10 1 352 1 1 10 10 353 1 1 10 5 354 2 1 10 1 355 2 1 10 9 356 2 1 10 5 357 4 1 10 1 358 4 1 10 5 359 5 1 10 1 360 5 1 10 -5 361 362 */
第三个:
1 /** 2 root 3 指针 4 **/ 5 #include6 #include 7 #include 8 #include 9 #include <string> 10 #include 11 #include 12 using namespace std; 13 #define ll long long 14 15 /** 16 log(n)=16 17 n*log(n)*log(n)=12800000 18 **/ 19 20 const double eps=1e-8; 21 const ll mod=1e9+7; 22 const int maxn=5e4+10; 23 const int maxf=maxn<<2; 24 const int maxg=maxn*18+maxf*2; 25 ///n * log(n)[larger] (每个点在log(n)个区间中出现) + 每个区间加上两个虚拟点(最小、最大) 26 27 struct node 28 { 29 int l,r,b; 30 }f[maxf]; 31 32 int par[maxg],son[maxg][2],val[maxg],cnt[maxg],siz[maxg]; 33 int a[maxn],id; 34 int minv=0,maxv=1e8,vir1=-2147483647,vir2=2147483647; 35 int *splay_value,root; 36 37 int chk(int x) 38 { 39 return son[par[x]][1]==x; 40 } 41 42 void pushup(int x) 43 { 44 siz[x]=siz[son[x][0]]+siz[son[x][1]]+cnt[x]; 45 } 46 47 void rotate(int x) 48 { 49 int y=par[x]; 50 int z=par[y]; 51 int k=chk(x); 52 int w=son[x][k^1]; 53 son[y][k]=w,par[w]=y; 54 son[z][chk(y)]=x,par[x]=z; 55 son[x][k^1]=y,par[y]=x; 56 pushup(y),pushup(x); 57 } 58 59 void splay(int x,int goal=0) 60 { 61 int y,z; 62 while (par[x]!=goal) 63 { 64 y=par[x]; 65 z=par[y]; 66 if (z!=goal) 67 { 68 if (chk(x)==chk(y)) 69 rotate(y); 70 else 71 rotate(x); 72 } 73 rotate(x); 74 } 75 if (!goal) 76 { 77 *splay_value=x; 78 root=x; 79 } 80 81 } 82 83 void find(int x) 84 { 85 if (!root) 86 return; 87 int cur=root; 88 while (son[cur][x>val[cur]] && x!=val[cur]) 89 cur=son[cur][x>val[cur]]; 90 splay(cur); 91 } 92 93 int pre(int x) 94 { 95 find(x); 96 if (val[root]<x) 97 return root; 98 int cur=son[root][0]; 99 while (son[cur][1]) 100 cur=son[cur][1]; 101 return cur; 102 } 103 104 int succ(int x) 105 { 106 find(x); 107 if (val[root]>x) 108 return root; 109 int cur=son[root][1]; 110 while (son[cur][0]) 111 cur=son[cur][0]; 112 return cur; 113 } 114 115 void insert(int x) 116 { 117 int cur=root,p=0; 118 while (cur && val[cur]!=x) 119 { 120 p=cur; 121 cur=son[cur][x>val[cur]]; 122 } 123 if (cur) 124 cnt[cur]++; 125 else 126 { 127 cur=++id; 128 if (p) 129 { 130 son[p][x>val[p]]=cur; 131 siz[p]++; 132 } 133 son[cur][0]=son[cur][1]=0; 134 val[cur]=x; 135 par[cur]=p; 136 cnt[cur]=siz[cur]=1; 137 } 138 splay(cur); 139 } 140 141 void remove(int x) 142 { 143 int last=pre(x); 144 int next=succ(x); 145 splay(last); 146 splay(next,last); 147 int del=son[next][0]; 148 if (cnt[del]>1) 149 { 150 cnt[del]--; 151 splay(del); 152 } 153 else 154 son[next][0]=0; 155 pushup(next),pushup(root); 156 } 157 158 //int kth(int &root,int k) 159 //{ 160 // int cur=root; 161 // while (1) 162 // { 163 // if (son[cur][0] && k<=siz[son[cur][0]]) 164 // cur=son[cur][0]; 165 // else if (k>siz[son[cur][0]]+cnt[cur]) 166 // { 167 // k-=siz[son[cur][0]]+cnt[cur]; 168 // cur=son[cur][1]; 169 // } 170 // else 171 // return cur; 172 // } 173 //} 174 175 int x_rank(int x) 176 { 177 find(x); 178 if (val[root]>=x) 179 return siz[son[root][0]]; 180 else 181 return siz[son[root][0]]+cnt[root]; 182 } 183 184 void seg_insert(int ind,int l,int r,int x,int y) 185 { 186 ///也可以build()函数,初始化 187 if (!f[ind].b) 188 { 189 root=f[ind].b; 190 splay_value=&f[ind].b; 191 insert(vir1); ///根节点编号为0 192 193 f[ind].b=id; ///根节点编号为id 194 root=f[ind].b; 195 splay_value=&f[ind].b; 196 insert(vir2); 197 } 198 root=f[ind].b; 199 splay_value=&f[ind].b; 200 insert(y); 201 if (l==r) 202 return; 203 int m=(l+r)>>1; 204 if (x<=m) 205 seg_insert(ind<<1,l,m,x,y); 206 else 207 seg_insert(ind<<1|1,m+1,r,x,y); 208 } 209 210 void seg_remove(int ind,int l,int r,int x,int y) 211 { 212 root=f[ind].b; 213 splay_value=&f[ind].b; 214 remove(y); 215 if (l==r) 216 return; 217 int m=(l+r)>>1; 218 if (x<=m) 219 seg_remove(ind<<1,l,m,x,y); 220 else 221 seg_remove(ind<<1|1,m+1,r,x,y); 222 } 223 224 int query_rank(int ind,int l,int r,int x,int y,int z) 225 { 226 if (x<=l && r<=y) 227 { 228 root=f[ind].b; 229 splay_value=&f[ind].b; 230 return x_rank(z)-1; ///减去最小虚拟点 231 } 232 int m=(l+r)>>1,sum=0; 233 if (x<=m) 234 sum+=query_rank(ind<<1,l,m,x,y,z); 235 if (m<y) 236 sum+=query_rank(ind<<1|1,m+1,r,x,y,z); 237 return sum; 238 } 239 240 int query_pre(int ind,int l,int r,int x,int y,int z) 241 { 242 if (x<=l && r<=y) 243 { 244 root=f[ind].b; 245 splay_value=&f[ind].b; 246 return val[pre(z)]; 247 } 248 int m=(l+r)>>1,re=vir1; 249 if (x<=m) 250 re=max(re,query_pre(ind<<1,l,m,x,y,z)); 251 if (m<y) 252 re=max(re,query_pre(ind<<1|1,m+1,r,x,y,z)); 253 return re; 254 } 255 256 int query_succ(int ind,int l,int r,int x,int y,int z) 257 { 258 if (x<=l && r<=y) 259 { 260 root=f[ind].b; 261 splay_value=&f[ind].b; 262 return val[succ(z)]; 263 } 264 int m=(l+r)>>1,re=vir2; 265 if (x<=m) 266 re=min(re,query_succ(ind<<1,l,m,x,y,z)); 267 if (m<y) 268 re=min(re,query_succ(ind<<1|1,m+1,r,x,y,z)); 269 return re; 270 } 271 272 int main() 273 { 274 int n,m,i,l,r,k,mode,x,L,R,mid; 275 scanf("%d%d",&n,&m); 276 for (i=1;i<=n;i++) 277 { 278 scanf("%d",&x); 279 seg_insert(1,1,n,i,x); 280 a[i]=x; 281 } 282 while (m--) 283 { 284 scanf("%d",&mode); 285 if (mode==3) 286 scanf("%d%d",&l,&k); 287 else 288 scanf("%d%d%d",&l,&r,&k); 289 if (mode==1) 290 ///log(n)*log(n) 291 printf("%d\n",query_rank(1,1,n,l,r,k)+1); ///比其小的点的数目+1 292 else if (mode==2) 293 { 294 ///log(value_range[maxv-minv]) 295 ///可离散化成log(maxn+maxm),但写起来很复杂 296 L=minv,R=maxv; 297 while (L<=R) 298 { 299 mid=(L+R)>>1; 300 ///log(n)*log(n) 301 x=query_rank(1,1,n,l,r,mid)+1; /// 302 if (x<=k) 303 L=mid+1; 304 else 305 R=mid-1; 306 } 307 printf("%d\n",R); 308 } 309 else if (mode==3) 310 { 311 ///log(n)*log(n) 312 seg_remove(1,1,n,l,a[l]); 313 ///log(n)*log(n) 314 seg_insert(1,1,n,l,k); 315 a[l]=k; 316 } 317 else if (mode==4) 318 ///log(n)*log(n) 319 printf("%d\n",query_pre(1,1,n,l,r,k)); 320 else 321 ///log(n)*log(n) 322 printf("%d\n",query_succ(1,1,n,l,r,k)); 323 } 324 return 0; 325 } 326 /* 327 9 100 328 4 2 2 1 9 4 0 1 1 329 330 1 1 5 1 331 1 1 5 2 332 1 1 5 3 333 1 1 5 4 334 1 1 5 5 335 336 2 1 5 1 337 2 1 5 2 338 2 1 5 3 339 2 1 5 4 340 2 1 5 5 341 342 3 3 0 343 1 1 5 3 344 3 3 1 345 1 1 5 3 346 3 3 2 347 1 1 5 3 348 3 3 3 349 1 1 5 3 350 3 3 5 351 1 1 5 3 352 3 3 10 353 1 1 5 3 354 3 3 2 355 356 4 1 5 0 357 4 1 5 1 358 4 1 5 2 359 4 1 5 3 360 4 1 5 4 361 4 1 5 5 362 363 5 1 5 0 364 5 1 5 1 365 5 1 5 2 366 5 1 5 3 367 5 1 5 4 368 5 1 5 9 369 5 1 5 10 370 371 372 9 100 373 1 1 1 1 1 1 1 1 1 374 1 1 10 1 375 1 1 10 10 376 1 1 10 5 377 2 1 10 1 378 2 1 10 9 379 2 1 10 5 380 4 1 10 1 381 4 1 10 5 382 5 1 10 1 383 5 1 10 -5 384 385 386 1 100 387 1 2 388 1 1 2 1 389 1 1 2 2 390 */
=========================================
AVL树、splay树(伸展树)和红黑树比较
https://blog.csdn.net/u010585135/article/details/41852945
实况:
AVL树时间上较慢,编程竞赛中一般不用AVL树
splay树时间上较为合适,但比红黑树稍慢,如java底层就使用红黑树编写
但由于红黑树编写极为复杂,所以编程比赛上一般不使用红黑树,而使用splay。
由于splay写起来也比较麻烦,所以有时会用其它方法替代splay,如替罪羊树,仙人掌树这些666的方法。