zoukankan      html  css  js  c++  java
  • 块状链表 学习笔记

    感谢大佬 @w33z8kqrqk8zzzx33

    用块状链表实现平衡树,是怎么回事呢?快来跟小编看看吧~

    前置知识

    vector 的部分用法

    vector 就是变长数组。由于 STL 制作者们八仙过海,所以它的一些操作常数极小(相比于普通数组)。

    首先注意,vec 的第一个位置下标是 0;而且大多函数都是左闭右开的(就像 sort 一样,你要写 sort(a+1,a+n+1) 而不是 sort(a+1,a+n),就是因为 sort(l,r) 的范围是 ([l,r))([l,r-1]))。

    • vec.begin() 它的第一个位置(如果你想知道 vec 第一个位置的数字是什么,你可以用 vec.front()vec[0])。

    • vec.end() 它的最后一个位置还要后一位(所以实际的最后一位是 --vec.end())(与 vec.front() 同理,最后一个位置的数字vec.back())。

    • vec[wei]wei 个位置的数字

    • vec.size() 它有多少个元素。

    • vec.emplace_back(x) 在它的最后放一个新数字 x(和 push_back 是一个东西),(O(1))

    • vec.emplace(wei,x) 在它的 wei 这个位置前面插入一个新位置,新位置的数字是 x(和 insert 是一个东西),极小常数的 (O(n))

    • vec.erase(wei) 删除 wei 这个位置,极小常数的 (O(n))

    • lower_bound(vec.begin(),vec.end(),x) 查询整个 vec 第一个大于等于 x 的数字的位置是什么。这个函数也是左闭右开的,但是因为 vec.end() 刚好指向最后一位的下一位,所以可以视作整个 vec(O(log n))

    • upper_bound(vec.begin(),vec.end(),x) 查询整个 vec 第一个大于 x 的数字的位置是什么。和上面同理。

    平衡树题意

    维护一个多重集合,需支持下列操作:

    1. 插入或删除一个数 (x)
    2. 查询 (x) 排名;
    3. 查询排名为 (x) 的数字是什么;
    4. 查询 (x) 的前驱/后继。

    块状链表

    我们想到一个暴力做法:维护一个 vec,使得里面的数字都是从小到大排好序的。

    对于四个操作:

    1. 二分 (x) 应该在的位置,暴力插入/删除。
    2. 二分 (x) 应该在的位置。
    3. cout<<vec[x]
    4. 二分 (x) 应该在的位置。

    瓶颈显然在于操作 1 ,是小常数 (O(n))

    那么考虑分块。为了方便,设 (B=sqrt n),分成了 B 个大小为 B 的块。

    然后二分 (x) 的位置,就可以转为另一个方法:

    依次遍历每个块,看一下块尾的元素是否小于 (x)。如果,则 (x) 的位置就在这个块中,在块内二分即可。这是 (O(B)) 的哟~

    暴力插入/删除的话,也变成了小常数 (O(B))(实测跑的飞快,就像发疯了的 (O(log n)) 一样!)。

    但是如果我们不停地在同一个块进行插入,这个块变得很大,会退化成 (O(n))

    解决方案是,如果有一个块的块长大于 (B) 了,那么就把它们掰成两个 (frac{B}{2}) 的块

    这样保证时间复杂度了,但是还有一些细节:

    1. 为了仍能保证块的大小顺序(即把所有块合成一起时,仍是从小到大排序的),我们需要用链表把所有的块串起来,这样掰开块的时候就是 (O(1)) 的了。
    2. 因为链表不支持定点访问,操作 3 的方法要改变了。设立当前排名 (cnt),我们一次遍历每一个块,就让 (cnt) 增加块的大小。如果 (cntge x) 了,代表就在当前块中,块内二分即可。
    3. 一开始把数列加进去的时候,是 (frac{B}{2}) 个为一组,放进块中。

    代码

    题目 【模板】普通平衡树

    链表可以直接用 vector 代替,也就是 vecvec!!1

    代码非常短,于是块状链表也被称作 “五分钟平衡树”。

    #include<bits/stdc++.h>
    #define rep(i,x,y) for(int i=x;i<=y;++i)
    #define ltor(id) kzlb[id].begin(),kzlb[id].end() 
    #define iter vector <int> ::iterator 
    #define pb emplace_back
    using namespace std;
    const int n7=101234,inf=1e7+1;
    int T,B;
    vector < vector <int> > kzlb;
    
    int rd(){
    	int shu=0;bool fu=0;char ch=getchar();
    	while( !isdigit(ch) ){if(ch=='-')fu=1;ch=getchar();}
    	while( isdigit(ch) )shu=(shu<<1)+(shu<<3)+ch-'0',ch=getchar();
    	return fu?-shu:shu;
    }
    
    void wt(int z){
    	if(z<0)putchar('-'),z=-z;
    	if(z>9)wt(z/10);
    	putchar(z%10+'0');
    }
    
    int ffind(int x){
    	rep(i,0,kzlb.size()-1){
    		if(kzlb[i].back()>=x)return i;
    	}
    }
    
    void isert(int x){
    	int id=ffind(x);
    	kzlb[id].emplace(lower_bound(ltor(id),x),x);
    	if(kzlb[id].size()>B){
    		kzlb.emplace(kzlb.begin()+id+1,kzlb[id].begin()+B/2, kzlb[id].end() );
    		kzlb[id].erase(kzlb[id].begin()+B/2, kzlb[id].end() );
    	}
    }
    
    void erase(int x){
    	int id=ffind(x);
    	kzlb[id].erase( lower_bound(ltor(id),x) );
    	if( !kzlb[id].size() )kzlb.erase(kzlb.begin()+id);
    }
    
    int Qkth(int x){
    	rep(i,0,kzlb.size()-1){
    		if(kzlb[i].size()>=x)return kzlb[i][x-1];
    		else x-=kzlb[i].size();
    	}
    }
    
    int Qnum(int x){
    	int cnt=0;
    	rep(i,0,kzlb.size()-1){
    		if(kzlb[i].back()>=x){
    			cnt+=lower_bound(ltor(i),x)-kzlb[i].begin();
    			return cnt+1;
    		}
    		else cnt+=kzlb[i].size();
    	}
    }
    
    int Qpre(int x){
    	int id=ffind(x);
    	iter wei=lower_bound(ltor(id),x);
    	if( wei==kzlb[id].begin() )return kzlb[id-1].back();
    	else return *--wei;
    }
    
    int Qnxt(int x){
    	int id=ffind(x+1);
    	iter wei=upper_bound(ltor(id),x);
    	//左闭右开,所以wei=end表示找不到 
    	if( wei==kzlb[id].end() )return kzlb[id+1].front();
    	else return *wei;
    }
    
    int main(){
    	kzlb.pb();
    	kzlb.back().pb(inf);
    	T=rd(),B=sqrt(T);
    	while(T--){
    		int sys=rd(),x=rd();
    		if(sys==1)isert(x);
    		if(sys==2)erase(x);
    		if(sys==3)wt( Qnum(x) ),putchar('
    ');
    		if(sys==4)wt( Qkth(x) ),putchar('
    ');
    		if(sys==5)wt( Qpre(x) ),putchar('
    ');
    		if(sys==6)wt( Qnxt(x) ),putchar('
    ');
    	} 
    	return 0;
    }
    
    
  • 相关阅读:
    HDU 1069 Monkey and Banana
    HDU 1029 Ignatius and the Princess IV
    HDU 1024 Max Sum Plus Plus
    Gym100923H Por Costel and the Match
    Codeforces 682C Alyona and the Tree
    Codeforces 449B Jzzhu and Cities
    Codeforces (ccpc-wannafly camp day2) L. Por Costel and the Semipalindromes
    Codeforces 598D (ccpc-wannafly camp day1) Igor In the Museum
    Codeforces 1167c(ccpc wannafly camp day1) News Distribution 并查集模板
    快乐数问题
  • 原文地址:https://www.cnblogs.com/BlankAo/p/14724158.html
Copyright © 2011-2022 走看看