[데이터 구조] 범 호 강 Treap (비 회전 평형 트 리) & 지속 가능 한 Treap 정리

범 호 강 Treap
이것 은 매우 신기 한 데이터 구조 이다.또 이런 데이터 구 조 는 쓰기 쉽다.
쉽게 말 하면 이런 treap 은 두 가지 조작 을 바탕 으로 한다.
Merge (int x, int y) -> x 의 하위 트 리 와 y 의 하위 트 리 를 합 쳐 x 를 만족 시 키 는 하위 트 리 의 최대 치 는 y 하위 트 리 의 최소 치 보다 작 고 복잡 도 O (logN) Split (int x, int k) -> x 의 최소 k 개 값/k 와 같은 값 을 다른 부분 과 분리 합 니 다. 복잡 도 O (logN)
먼저 Merge 작업: 이미 알 고 있 는 x 의 서브 트 리 의 최대 치 는 y 서브 트 리 의 최소 치보다 작 기 때문에 반드시 y 가 x 의 오른쪽 아들 노드 에 연결 되 거나 x 가 y 의 왼쪽 아들 노드 (상세 한 코드 참조) 에 연결 되 어 깊이 를 최대한 작 게 하기 위해 우 리 는 무 작위 수 를 사용 하여 x 를 y 의 아들 로 판단 하거나 y 를 x 의 아들 로 판단 한다.
int Merge(int x,int y){
    if(x==0) return y;
    if(y==0) return x;
    if(Tree[x].fix<Tree[y].fix){
        Tree[x].ch[1]=Merge(Tree[x].ch[1],y);// y  x      
        update(x);
        return x;
    }
    else{
        Tree[y].ch[0]=Merge(x,Tree[y].ch[0]);// x  y     
        update(y);
        return y;
    }
}

다음은 Split 작업 (두 가지 다른 Split 방식 이 있 습 니 다. 제목 에 따라 스스로 적당 한 하 나 를 선택 할 수 있 습 니 다) 먼저 우 리 는 이 나 무 를 두 부분 으로 나 누 어야 합 니 다. 아래 코드 에서 first 는 앞부분 이 고 second 는 후반 부분 입 니 다.
pair<int,int> Split(int x,int k){
    if(x==0) return make_pair(0,0);
    pair<int,int> y;
    if(Tree[x].key<=k){//         k     
        y=Split(Tree[x].ch[1],k);//x         k   , x              ,             
        Tree[x].ch[1]=y.first;// x     x         ,
        update(x);
        y.first=x;
    }
    else{//       
        y=Split(Tree[x].ch[0],k);
        Tree[x].ch[0]=y.second;
        update(x);
        y.second=x;
    }
    return y;
}

두 번 째:
pair<int,int> Split(int x,int k){
    if(x==0) return make_pair(0,0);
    pair<int,int> y;
    if(Tree[Tree[x].ch[0]].sum<k){//      k     (         k )
        y=Split(Tree[x].ch[1],k);
        Tree[x].ch[1]=y.first;
        update(x);
        y.first=x;
    }
    else{
        y=Split(Tree[x].ch[0],k);
        Tree[x].ch[0]=y.second;
        update(x);
        y.second=x;
    }
    return y;
}

이제 이 두 가지 조작 을 바탕 으로 우 리 는 균형 트 리 를 쓸 수 있 습 니 다. (쓰기 쉽 지 않 습 니까?!) 그러면 먼저 삽입 작업 입 니 다.
void Insert(int val){
    pair<int,int> x=Split(root,val);
    Tree[++ncnt]=node(val);//   
    Tree[ncnt].ch[0]=0;
    Tree[ncnt].ch[1]=0;
    root=Merge(Merge(x.first,ncnt),x.second);
}

쉽 죠?
그 다음 삭제 작업:
void Del(int val){
    pair<int,int> x=Split(root,val);
    pair<int,int> y=Split(x.first,val-1);
    y.second=Merge(Tree[y.second].ch[0],Tree[y.second].ch[1]);
    root=Merge(Merge(y.first,y.second),x.second);
}

쉽 죠?
하나 더: 밸 런 스 트 리 의 k 작은 수 를 구하 세 요.
int find_id(int x,int k){
    if(x==0)
        return 0;
    int ch0=Tree[x].ch[0];
    if(Tree[ch0].sum>=k)
        return find_id(ch0,k);
    if(Tree[ch0].sum+1>=k)
        return Tree[x].key;
    return find_id(Tree[x].ch[1],k-Tree[ch0].sum-1);
}

어?사실 이 건 보통 밸 런 스 트 리 와 다 르 지 않 은 것 같 아...
밸 런 스 트 리 에서 val 의 순 위 를 구 합 니 다. (이 값 은 트 리 에 없 을 수 있 습 니 다)
int get_kth(int k){
	//  Split    k   ,      int k1=find_id(root,k);     k-1  k1
    pair<int,int> x=Split(root,k-1);//  Split      k      
    int ans=Tree[x.first].sum+1;
    root=Merge(x.first,x.second);
    return ans;
}

쉽 지 않 아 요??한 마디 로 하면, 이것 은 상당히 쓰기 좋 은 밸 런 스 트 리 입 니 다. 아직 익숙 하지 않 으 면, cqoi 의 일반 밸 런 스 트 리 를 몇 번 더 만 들 수 있 습 니 다.
지속 가능 한 Treap
사실, 만약 당신 이 다른 지속 가능 한 데이터 구 조 를 배 웠 다 면, 이 부분 은 매우 간단 할 것 입 니 다.
사실 주석 트 리 와 마찬가지 로 우 리 는 n 개의 루트 노드 만 사용 하고 삽입 할 때마다 경로 의 모든 노드 를 복사 하면 됩 니 다. 이것 은 지속 가능 한 Split 입 니 다.
pair<int,int> Split(int x,int k){
    if(x==0)
        return make_pair(0,0);
    int newone;
    pair<int,int> y;
    if(Tree[x].key<=k){
        newone=++ncnt;
        Tree[newone]=Tree[x];
        y=Split(Tree[newone].ch[1],k);
        Tree[newone].ch[1]=y.first;
        update(newone);
        y.first=newone;
    }
    else{
        newone=++ncnt;
        Tree[newone]=Tree[x];
        y=Split(Tree[newone].ch[0],k);
        Tree[newone].ch[0]=y.second;
        update(newone);
        y.second=newone;
    }
    return y;
}

그러나 가끔 Merge 작업 은 새로운 노드 를 복사 할 필요 가 없습니다. 이 유 는 간단 합 니 다. 만약 에 Merge 의 두 개의 키 트 리 가 같은 시간 버 전에 있다 면 새로운 노드 를 복사 할 필요 가 없습니다.
int Merge(int x,int y){
    if(x==0) return y;
    if(y==0) return x;
    if(Tree[x].fix<Tree[y].fix){
        Tree[x].ch[1]=Merge(Tree[x].ch[1],y);
        update(x);
        return x;
    }
    else{
        Tree[y].ch[0]=Merge(x,Tree[y].ch[0]);
        update(y);
        return y;
    }
}

예제: 로 곡 3835 일반 지구 화 밸 런 스 트 리
#include
#include
#include
#include
#define SF scanf
#define PF printf
#define MAXN 500010
using namespace std;
struct node{
    int ch[2];
    int key,sum,fix;
    node () {}
    node (int key1):key(key1),fix(rand()),sum(1) {}
}Tree[MAXN*30];
int ncnt,root[MAXN];
void update(int x){
    Tree[x].sum=Tree[Tree[x].ch[0]].sum+Tree[Tree[x].ch[1]].sum+1;
}
int Merge(int x,int y){
    if(x==0) return y;
    if(y==0) return x;
    if(Tree[x].fix<Tree[y].fix){
        Tree[x].ch[1]=Merge(Tree[x].ch[1],y);
        update(x);
        return x;
    }
    else{
        Tree[y].ch[0]=Merge(x,Tree[y].ch[0]);
        update(y);
        return y;
    }
}
pair<int,int> Split(int x,int k){
    if(x==0)
        return make_pair(0,0);
    int newone;
    pair<int,int> y;
    if(Tree[x].key<=k){
        newone=++ncnt;
        Tree[newone]=Tree[x];
        y=Split(Tree[newone].ch[1],k);
        Tree[newone].ch[1]=y.first;
        update(newone);
        y.first=newone;
    }
    else{
        newone=++ncnt;
        Tree[newone]=Tree[x];
        y=Split(Tree[newone].ch[0],k);
        Tree[newone].ch[0]=y.second;
        update(newone);
        y.second=newone;
    }
    return y;
}
int find_kth(int now,int val){
    pair<int,int> x=Split(root[now],val-1);
    int ans=Tree[x.first].sum+1;
    root[now]=Merge(x.first,x.second);
    return ans;
}
int get_kth(int x,int k){
    if(x==0)
        return 0;
    int ch0=Tree[x].ch[0];
    if(Tree[ch0].sum>=k)
        return get_kth(ch0,k);
    if(Tree[ch0].sum+1==k)
        return Tree[x].key;
    return get_kth(Tree[x].ch[1],k-Tree[ch0].sum-1);
}
int get_pre(int now,int val){
    int k=find_kth(now,val);
    return get_kth(root[now],k-1);
}
int get_bac(int now,int val){
    pair<int,int> x=Split(root[now],val);
    int ans=get_kth(x.second,1);
    root[now]=Merge(x.first,x.second);
    return ans;
}
void Insert(int val,int now){
    pair<int,int> x=Split(root[now],val);
    Tree[++ncnt]=node(val);
    Tree[ncnt].ch[0]=0;
    Tree[ncnt].ch[1]=0;
    root[now]=Merge(Merge(x.first,ncnt),x.second);
}
void Delete(int val,int now){
    pair<int,int> x=Split(root[now],val);
    pair<int,int> y=Split(x.first,val-1);
    if(Tree[y.second].key==val)
        y.second=Merge(Tree[y.second].ch[0],Tree[y.second].ch[1]);
    root[now]=Merge(Merge(y.first,y.second),x.second);
}
int n,las,x,tag;
int main(){
    SF("%d",&n);
    Insert(-2147483647,0);
    Insert(2147483647,0);
    for(int i=1;i<=n;i++){
        SF("%d%d%d",&las,&tag,&x);
        if(Tree[root[las]].sum!=0){
            root[i]=++ncnt;
            Tree[root[i]]=Tree[root[las]];
        }
        if(tag==1)
            Insert(x,i);
        if(tag==2)
            Delete(x,i);
        if(tag==3)
            PF("%d
"
,find_kth(i,x)-1); if(tag==4) PF("%d
"
,get_kth(root[i],x+1)); if(tag==5) PF("%d
"
,get_pre(i,x)); if(tag==6) PF("%d
"
,get_bac(i,x)); } }

지침 판
#include
#include
#include
#include
#define SF scanf
#define PF printf
#define MAXN 500010
#define INF 2147483647
using namespace std;
struct node{
	node *ch[2];
	int val,sum,fix;
	void pushup(){
		sum=ch[0]->sum+ch[1]->sum+1;	
	}
}Tree[MAXN*24];
node *NIL=Tree,*ncnt=Tree;
typedef pair<node*,node*> PNN;
void Newnode(node *x,int val){
	x->val=val;
	x->sum=1;
	x->fix=rand();
	x->ch[0]=x->ch[1]=NIL;	
}
void init(){
	NIL->ch[0]=NIL->ch[1]=NIL;	
}
node *Merge(node *x,node *y){
	if(x==NIL)
		return y;
	if(y==NIL)
		return x;
	if(x->fix>y->fix){
		x->ch[1]=Merge(x->ch[1],y);
		x->pushup();
		return x;
	}
	else{
		y->ch[0]=Merge(x,y->ch[0]);
		y->pushup();
		return y;
	}
}
PNN Split(node *x,int val){
	if(x==NIL)
		return make_pair(NIL,NIL);
	node *newp=++ncnt;
	PNN y;
	if(x->val<=val){
		*newp=*x;
		y=Split(x->ch[1],val);
		newp->ch[1]=y.first;
		newp->pushup();
		y.first=newp;
	}
	else{
		*newp=*x;
		y=Split(x->ch[0],val);
		newp->ch[0]=y.second;
		newp->pushup();
		y.second=newp;
	}
	return y;
}
void Ins(node *&rt,int val){
    PNN y=Split(rt,val);
    Newnode(++ncnt,val);
    node *x=ncnt;
    node *z=Merge(x,y.second);
    rt=Merge(y.first,z);
}   
void Del(node *&rt,int val){
    PNN x=Split(rt,val);
    PNN y=Split(x.first,val-1);
    if(y.second->val==val)
		y.second=Merge(y.second->ch[0],y.second->ch[1]);
    rt=Merge(Merge(y.first,y.second),x.second); 
}
node *find_kth(node *x,int k){
    if(x==NIL)
        return x;
    if(x->ch[0]->sum>=k)
        return find_kth(x->ch[0],k);
    if(x->ch[0]->sum+1>=k)
        return x;
    return find_kth(x->ch[1],k-(x->ch[0]->sum)-1);
}
node *find_nxt(node *x,int d){
    while(x->ch[d]!=NIL)
        x=x->ch[d];
    return x;
}
node *root[MAXN];
int n;
int main(){
	SF("%d",&n);
	init();
	root[0]=NIL;
	Ins(root[0],-INF);
	Ins(root[0],INF);
	int las,tag,x;
	for(int i=1;i<=n;i++){
		SF("%d%d%d",&las,&tag,&x);
		root[i]=++ncnt;
		*root[i]=*root[las];
		if(tag==1)
			Ins(root[i],x);
		if(tag==2)
			Del(root[i],x);
		if(tag==3){
            PNN y=Split(root[i],x-1);
            PF("%d
"
,y.first->sum); root[i]=Merge(y.first,y.second); } if(tag==4){ x++; PF("%d
"
,find_kth(root[i],x)->val); } if(tag==5){ PNN y=Split(root[i],x-1); PF("%d
"
,find_nxt(y.first,1)->val); root[i]=Merge(y.first,y.second); } if(tag==6){ PNN y=Split(root[i],x); PF("%d
"
,find_nxt(y.second,0)->val); root[i]=Merge(y.first,y.second); } } }

좋은 웹페이지 즐겨찾기