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

4 篇文章 0 订阅
4 篇文章 0 订阅

我还是太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);
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值