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

来源:互联网 发布:c语言运行快捷键 编辑:程序博客网 时间:2024/05/01 03:05

我还是太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);    }}
原创粉丝点击