skip list - 跳躍表詳註,常數小
阿新 • • 發佈:2018-10-11
指定 != ide sed scanf splay 技術 rand name
跳躍表詳註
具體看註釋代碼
luoguP3369: https://www.luogu.org/recordnew/show/11782419
1 #include<bits/stdc++.h> 2 #define repeat(a,b,c,d) for (int a=b;a<=c;a+=d) 3 using namespace std; 4 struct node{ 5 int nxt,dwn,jmp,val; 6 }a[100000 * 4]; 7 int al = 0,n,first; 8 const int maxdep = 9, INF = 1e9; 9 inline voidSkip Listbuild(){//在程序開始時調用,建造一個dep=maxdep的表 10 for (register int i=1;i<=maxdep;i++){//建造開始節點 11 a[++al].nxt = maxdep + i;//指向最後節點 12 if (i != 1) a[al].dwn = al-1;//非第一個節點指向下一個down節點 13 else a[al].dwn = -1;//最後一個 14 a[al].jmp = 0;a[al].val = -INF;//賦值,a[al].jmp可以任意賦。 15 } 16 first = al;//指向第一個節點 17 for (register int i=1;i<=maxdep;i++){ 18 a[++al].nxt = -1;//same 19 if (i != -1) a[al].dwn = al-1; 20 a[al].jmp = INF;a[al].val = INF; 21 } 22 } 23 //之後我們維護NOW指針。 24 inline int dfs_insert(int x,int NOW,int dep,int insdep){//為了常數優化,不先調用find_k_rank_and_p找位置,而是直接遞歸位置。25 if (dep == 0) return 0;//邊界 26 register int len_jmp = 0;//我們從現在NOW指針往前蹦的長度 27 while (x > a[a[NOW].nxt].val) len_jmp += a[NOW].jmp, NOW = a[NOW].nxt;//**記住,所有的skip list的搜索都是開區間的!** 28 register int lft_jmp = dfs_insert(x,a[NOW].dwn,dep-1,insdep);//搜到下一層 29 if (dep > insdep) a[NOW].jmp++;//如果沒達到指定層數,只是NOW的jmp指針增加 30 else{ 31 a[++al].nxt = a[NOW].nxt;a[NOW].nxt = al;a[al].dwn = al-1;a[al].val = x;//維護指針 32 a[al].jmp = a[NOW].jmp - lft_jmp;a[NOW].jmp = lft_jmp + 1;//一並維護NOW 33 } 34 return len_jmp + lft_jmp;//返回跳過的層數。 35 } 36 inline void insert(int x){ 37 register int insdep = 1,random = rand()<<16|rand();//**千萬不要rand來rand去,賊慢! 38 while (random%4 == 0) insdep++,random/=4;dfs_insert(x,first,maxdep,insdep);//親測4層最快 39 } 40 inline pair<int,int> find_k_rank_and_p(int x){ 41 register int NOW = first,len = 0,dep = maxdep;//尋找x的rank並且返回NOW指針(全部開區間) 42 while (dep > 0){ 43 while (x > a[a[NOW].nxt].val) len += a[NOW].jmp, NOW = a[NOW].nxt;//能走則走 44 dep--;//維護層數 45 if (dep == 0) break;//為了維護NOW,一旦dep==0就break; 46 NOW = a[NOW].dwn; 47 } 48 return make_pair(len+1,NOW);//len是開區間,要+1 49 } 50 inline void del(int x){ 51 register int rank = find_k_rank_and_p(x).first,NOW = first,len = 0,dep = maxdep;//刪除時先找出要刪的位置,必須保證不多刪。 52 while (dep > 0){ 53 while (x > a[a[NOW].nxt].val) len += a[NOW].jmp, NOW = a[NOW].nxt;//找 54 if (a[a[NOW].nxt].val == x && len + a[NOW].jmp == rank) // be del 55 a[NOW].jmp = a[NOW].jmp + a[a[NOW].nxt].jmp - 1,a[NOW].nxt = a[a[NOW].nxt].nxt;//維護NOW指針 56 else a[NOW].jmp--; 57 NOW = a[NOW].dwn; 58 dep--; 59 } 60 } 61 inline int find_rank_val(int x){ 62 register int NOW = first,len = 0,dep = maxdep; 63 while (dep > 0){ 64 while (x > len + a[NOW].jmp) 65 len += a[NOW].jmp, NOW = a[NOW].nxt;//能蹦則蹦 66 dep--; 67 if (dep == 0) break; 68 NOW = a[NOW].dwn; 69 } 70 return a[a[NOW].nxt].val;//返回值 71 } 72 int main(){ 73 srand(time(NULL)); 74 build(); 75 scanf("%d",&n); 76 for (int i=1;i<=n;i++){ 77 register int opt,x; 78 scanf("%d%d",&opt,&x); 79 if (opt == 1) insert(x);//插入 80 if (opt == 2) del(x);//刪除 81 if (opt == 3) printf("%d\n",find_k_rank_and_p(x).first);//查找x數位置 82 if (opt == 4) printf("%d\n",find_rank_val(x));//查找rank為x的值 83 if (opt == 5) printf("%d\n",a[find_k_rank_and_p(x).second].val);//求x的前驅 84 if (opt == 6) printf("%d\n",a[a[find_k_rank_and_p(x+1).second].nxt].val);//求x的後綴 85 } 86 }
skip list - 跳躍表詳註,常數小