【小學生數據結構】樹【並查集】史

我還是太NAIVE了
一道並查集的題又對拍又眼調還花了3hQAQ

題目大意

關於並查集的合併與查詢祖先,要維護時間戳,強制在線

要維護一個固定的值,顯然我們不能路徑壓縮,至於合併有兩種方法(複雜度都是nlogn)
一種是啓發式合併,每次按size從小的往大的合併
另一種是按秩合併,就是dep從底往上遞增

因爲沒有路徑壓縮,所以要存Fa()的返回值

核心程序

啓發式合併

void Merge(int p,int q){
    num++;
    int u=Fa(p,INF),v=Fa(q,INF);
    if(u==v)return ;
    if(sz[u]<sz[v])swap(u,v);
    f[v]=num;
    sz[u]+=sz[v];
    fa[v]=u;
}

按秩合併

void Merge(int p,int q){
    num++;
    int u=Fa(p,INF),v=Fa(q,INF);
    if(u==v)return ;
    if(d[u]<d[v])swap(u,v);
    f[v]=num;
    d[u]=max(d[u],d[v]+1);
    fa[v]=u;
}

FindFather

lim是題目的限制時間戳
如果要判斷是否在同一個並查集就比較Fa(p,INF)和Fa(q,INF)是否相等

int Fa(int x,int lim){
    return (fa[x]!=x)&&(f[x]<=lim)?Fa(fa[x],lim):x;
}

題目大意

插點到一棵空二叉查找樹中,查詢的節點深度和

分析

可以在線用set/map維護,l和r表示now的左右迭代器,時間O(nlogn)

dep【*now】=max(dep【*l】,dep【*r】)+1

或者每次找到最先插入的點,遞歸找左右子樹
這個用rmq/線段樹維護插入順序區間最小值就可以做到O(nlogn)

附上map做法的程序

#include<cstdio>
#include<map>
#include<algorithm>
#define se second
#define fr first
#define mp(p,q) make_pair(p,q)
using namespace std;
typedef long long LL;
LL ans;
map<int,int>M;
int n,p;
map<int,int>::iterator l,r;
int main(){
    scanf("%d",&n);
    M[0]=-1;
    M[n+1]=-1;
    for(int i=1;i<=n;i++){
        scanf("%d",&p);
        M[p]=0;
        l=r=M.lower_bound(p);
        M[p]=max((*(--l)).se,(*(++r)).se)+1;
//      printf("%d %d %d %d\n",(*l).fr,(*r).fr,(*l).se,(*r).se);
        ans+=M[p];
        printf("%lld\n",ans);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章