SBT 노트 와 템 플 릿
void maintain(int &r,bool flag)
{
if(!flag)
{
if(tree[tree[r].rc].sz<tree[tree[tree[r].lc].lc].sz)zig(r);
else if(tree[tree[r].rc].sz<tree[tree[tree[r].lc].rc].sz)zagzig(r);
else return;
}
else
{
if(tree[tree[r].lc].sz<tree[tree[tree[r].rc].rc].sz)zag(r);
else if(tree[tree[r].lc].sz<tree[tree[tree[r].rc].lc].sz)zigzag(r);
else return;
}
maintain(tree[r].lc,0);
maintain(tree[r].rc,1);
maintain(r,0);
maintain(r,1);
}
그리고 AVL 의 maintain 은 이렇게 생 겼 습 니 다.
void maintain(int &r)
{
if(tree[tree[r].lc].h==tree[tree[r].rc].h+2)
{
int t=tree[r].lc;
if(tree[tree[t].lc].h==tree[tree[r].rc].h+1)r=zig(r);
else if(tree[tree[t].rc].h==tree[tree[r].rc].h+1)r=zagzig(r);
}
else if(tree[tree[r].rc].h==tree[tree[r].lc].h+2)
{
int t=tree[r].rc;
if(tree[tree[t].rc].h==tree[tree[r].lc].h+1)r=zag(r);
else if(tree[tree[t].lc].h==tree[tree[r].lc].h+1)r=zigzag(r);
}
tree[r].h=max(tree[tree[r].lc].h,tree[tree[r].rc].h)+1;
}
발견 할 수 있 는 것 은 1. AVL 과 SBT 는 모두 회전 이 있 고 한 번 의 회전 과 두 번 의 회전 이 있 지만 판단 조건 은 h 에서 size 2. AVL 로 현재 의 r 만 유지 하고 SBT 는 여러 번 유지 해 야 한다. 비록 O (1) 의 3. SBT 의 maintain 은 왼쪽 이 든 오른쪽 이 든 왼쪽 이 0 이 고 오른쪽 이 1 이다.그렇다면 기억 에 있어 서 SBT 는 여러 번 (뿌리 좌우 모두 maintain, 왼쪽 아들 은 왼쪽, 오른쪽 아들 오른쪽 만 유지) 해 야 한 다 는 것 만 기억 하고 SBT 의 회전 판단 조건 도 있다.왼쪽 아들 의 왼쪽 아들 이 오른쪽 아들 보다 크 면 우회전 한다.왼쪽 아들 의 오른쪽 아들 이 오른쪽 아들 보다 크 면 먼저 왼쪽으로 돌 고 오른쪽으로 돌 면 이것 은 AVL 의 저것 과 매우 유사 하 다.
2. insert 는 이 진 트 리 를 찾 는 insert 입 니 다. 게다가 size 를 유지 하고 마지막 에 maintain 이 있 습 니 다.
void insert(int &r,int x)
{
if(r==0)
{
tree[++cnt].sz=1;
tree[cnt].v=x;
r=cnt;
return;
}
++tree[r].sz;
if(x<tree[r].v)insert(tree[r].lc,x);
else insert(tree[r].rc,x);
maintain(r,x>=tree[r].v);
}
3. del 은 이 진 트 리 를 찾 는 del 이 고 유지 size 입 니 다.유지 하지 않 고 오히려 빨리 해 야 한다.이곳 은 유지 하지 않 고 마음대로 지 워 도 나무의 높이 는 변 하지 않 기 때문에 이 진 트 리 를 찾 는 성질 이 변 하지 않 고 시간 복잡 도 는 적어도 증가 하지 않 으 며 유지 하지 않 으 면 오히려 상수 시간 을 절약 할 수 있 기 때문이다.
int del(int &r,int x)
{
int res;
--tree[r].sz;
if(tree[r].v==x||(x<tree[r].v&&tree[r].lc==0)||(x>tree[r].v&&tree[r].rc==0))
{
res=tree[r].v;
if(0==tree[r].lc||0==tree[r].rc)r=tree[r].lc+tree[r].rc;
else tree[r].v=del(tree[r].lc,x);
}
else
{
if(x<tree[r].v)res=del(tree[r].lc,x);
else res=del(tree[r].rc,x);
}
return res;
}
4. SBT 를 중시 할 수 있 습 니 다. 사실 위 에 있 는 insert 는 SBT 를 중시 할 수 있 는 실현 입 니 다.SBT 로 하여 금 두 가지 생각 을 다시 하 게 하 다.1. tot 도 메 인 을 추가 하고 이 노드 가 몇 번 삽입 되 었 는 지 기록 합 니 다.그리고 많은 부분 을 수정 해 야 합 니 다. 예 를 들 어 삽입 할 때 r! =0 은 3 가지 상황 으로 나 누 어 tree [r]. v > x 는 왼쪽 하위 트 리, tree [r]. v < x 는 오른쪽 하위 트 리, tree [r]. v = = x 는 tree [r]. tot + + 그리고 del 일 때 이 점 의 tot 값 > 1 이면 바로 tot, tot = = 1 이면 점 을 삭제 합 니 다.그리고 del 은 2 원 그룹 으로 돌아 가 tot 와 v 를 기록 해 야 합 니 다.순 위 를 구하 자 면 K 가 컸 을 때 도 수정 이 있 었 다.선구자 후 계 는 수정 할 필요 가 없다.어쨌든 실현 은 비교적 번거롭다.
int kth(int r,int k)
{
if(k>=tree[tree[r].rc].sz+1&&k<=tree[tree[r].rc].sz+tree[r].tot)return tree[r].v;
if(k<1+tree[tree[r].rc].sz)return kth(tree[r].rc,k);
else return kth(tree[r].lc,k-tree[r].tot-tree[tree[r].rc].sz);
}
그 다음 에 아버 지 를 더 괴 롭 히 는 것 이 바로 size 의 이의 성 이다. SBT 의 size 는 노드 의 개수 이 고 k 가 큰 size 는 삽 입 된 몇 개의 수 이 며 SBT 를 중시 하 는 것 은 다르다.따로 지 켜 야 합 니 다.하지만 유지 하지 않 아 도 될 것 같 습 니 다. 특별한 균형 이 아 닙 니까?2. 같은 값 을 다른 값 으로 삽입 하면 위의 insert 입 니 다. x = = tree [r]. v 가 있 으 면 x 를 오른쪽 트 리 에 삽입 합 니 다 (물론 왼쪽 트 리 도 가능 합 니 다).이 때 이 진 트 리 의 의 미 를 찾 는 데 변화 가 생 겼 습 니 다. 이 나무의 중간 순 서 는 점점 늘 어 나 는 것 이 아니 라 줄 어 들 지 않 습 니 다.이렇게 쓰 면 tot 도 메 인 을 추가 로 열지 않 아 도 되 고, 2 개의 의미 가 다른 size 를 유지 하지 않 아 도 됩 니 다.insert 와 delete 도 별로 고 칠 필요 가 없습니다.그러나 이렇게 쓰 려 면 선구자 가 k 대 와 rank 에 이 어 어느 쪽으로 돌아 가 는 지 잘 고려 해 야 한다.구체 적 으로 코드 를 보 세 요.일반 밸 런 스 트 리 코드:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
struct node{
int lc,rc,sz,v;
}tree[500010];
int n,op,x,pred,succ,cnt,rt;
char c;
inline void GET(int &n)
{
n=0;
int f=1;
do{c=getchar();if(c=='-')f=-1;}while(c>'9'||c<'0');
while(c<='9'&&c>='0'){n=n*10+c-'0';c=getchar();}
n*=f;
}
inline void zig(int &r)
{
int t=tree[r].lc;
tree[r].lc=tree[t].rc;
tree[t].rc=r;
tree[r].sz=tree[tree[r].lc].sz+tree[tree[r].rc].sz+1;
tree[t].sz=tree[tree[t].lc].sz+tree[tree[t].rc].sz+1;
r=t;
}
inline void zag(int &r)
{
int t=tree[r].rc;
tree[r].rc=tree[t].lc;
tree[t].lc=r;
tree[r].sz=tree[tree[r].lc].sz+tree[tree[r].rc].sz+1;
tree[t].sz=tree[tree[t].lc].sz+tree[tree[t].rc].sz+1;
r=t;
}
inline void zigzag(int &r)
{
zig(tree[r].rc);
zag(r);
}
inline void zagzig(int &r)
{
zag(tree[r].lc);
zig(r);
}
inline void maintain(int &r,bool flag)
{
if(!flag)
{
if(tree[tree[r].rc].sz<tree[tree[tree[r].lc].lc].sz)zig(r);
else if(tree[tree[r].rc].sz<tree[tree[tree[r].lc].rc].sz)zagzig(r);
else return;
}
else
{
if(tree[tree[r].lc].sz<tree[tree[tree[r].rc].rc].sz)zag(r);
else if(tree[tree[r].lc].sz<tree[tree[tree[r].rc].lc].sz)zigzag(r);
else return;
}
maintain(tree[r].lc,0);
maintain(tree[r].rc,1);
maintain(r,0);
maintain(r,1);
}
void insert(int &r,int x)
{
if(r==0)
{
tree[++cnt].sz=1;
tree[cnt].v=x;
r=cnt;
return;
}
++tree[r].sz;
if(x<tree[r].v)insert(tree[r].lc,x);
else insert(tree[r].rc,x);
maintain(r,x>=tree[r].v);
}
int del(int &r,int x)
{
int res;
--tree[r].sz;
if(tree[r].v==x||(x<tree[r].v&&tree[r].lc==0)||(x>tree[r].v&&tree[r].rc==0))
{
res=tree[r].v;
if(0==tree[r].lc||0==tree[r].rc)r=tree[r].lc+tree[r].rc;
else tree[r].v=del(tree[r].lc,x);
}
else
{
if(x<tree[r].v)res=del(tree[r].lc,x);
else res=del(tree[r].rc,x);
}
return res;
}
void predecessor(int r,int x)
{
if(r==0)return;
if(x<=tree[r].v)predecessor(tree[r].lc,x);
else
{
if(x!=tree[r].v)pred=tree[r].v;
predecessor(tree[r].rc,x);
}
}
void successor(int r,int x)
{
if(r==0)return;
if(x<tree[r].v)
{
if(x!=tree[r].v)succ=tree[r].v;
successor(tree[r].lc,x);
}
else successor(tree[r].rc,x);
}
int kth(int r,int x)
{
if(x==tree[tree[r].lc].sz+1)return tree[r].v;
if(x<tree[tree[r].lc].sz+1)return kth(tree[r].lc,x);
return kth(tree[r].rc,x-tree[tree[r].lc].sz-1);
}
int rnk(int r,int x)
// x , 1 1 1 2 2 3 3,rnk(rt,2)=4
{
if(r==0)return 1;
if(x<=tree[r].v)return rnk(tree[r].lc,x);
return rnk(tree[r].rc,x)+tree[tree[r].lc].sz+1;
}
int main()
{
GET(n);
while(n--)
{
GET(op);GET(x);
if(op==1)insert(rt,x);
else if(op==2)del(rt,x);
else if(op==3)printf("%d
",rnk(rt,x));
else if(op==4)printf("%d
",kth(rt,x));
else if(op==5){predecessor(rt,x);printf("%d
",pred);}
else if(op==6){successor(rt,x);printf("%d
",succ);}
}
}
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
정수 반전Udemy 에서 공부 한 것을 중얼거린다 Chapter3【Integer Reversal】 (예) 문자열로 숫자를 반전 (toString, split, reverse, join) 인수의 수치 (n)가 0보다 위 또는 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.