【小学生数据结构】树【并查集】史

我还是太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]

按秩合并

void Merge(int p,int q){
    num++;
    int u=Fa(p,INF),v=Fa(q,INF);
    if(u==v)return ;
    if(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
#include
#include
#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);
    }
}

你可能感兴趣的:(gfoj,线段树,离散化,并查集,合并,数据结构)