zoukankan      html  css  js  c++  java
  • Prufer序列

    Prufer 序列

    作用

    将带标号 (n) 节点树用 (n-2)([1,n]) 的整数表示,

    (n) 个点的完全图的生成树和长度为 (n-2) 的值域为 ([1,n]) 的数列构成的双射。

    Cayley 定理,(n) 个点有标号生成树共 (n^{n-2}) 个。Anne's game

    算法

    树转 Prufer 序列

    每次选择一个编号最小的叶节点删除,记录它的父亲。

    重复 (n-2) 次以后剩下两个节点,算法结束。

    堆:(O(nlog n))

    指针:(O(n))

    指针指向编号最小的叶节点,每次删掉以后,

    • 如果产生了新的叶节点,且编号比已经填写完的更小,就直接继续删掉

    • 否则++,找到下一个编号最小的叶节点。

    Prufer 序列转树

    可以得到原树上每个点的度数。

    每次选择一个编号最小的度数为1的节点,与当前枚举的Prufer序列的点连接,然后同时减掉两个点的度数,重复 (n-2) 次后剩下两个度数为1的点,其中一个是 (n) ,连接他们即可。

    堆: (O(nlog n))

    指针:(O(n))

    具体而言,指针指向编号最小的度数为 1 的节点。

    每次将它与当前枚举到的 Prufer 序列的点连接之后,

    • 如果产生了新的度数为 1 的节点且编号比当前处理“完”的更小,则直接继续将它与下一个 Prufer 序列的点连接,
    • 否则++,找到下一个编号最小的度数为 1 的节点。

    实现

    【模板】Prufer 序列

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=5e6+10;
    int n,tp,f[N],p[N],d[N];
    ll ans=0;
    void Tree_Prufer(){
        for(int i=1;i<=n-1;i++) scanf("%d",&f[i]),d[f[i]]++;
        for(int i=1,j=1;i<=n-2;i++,j++){
            while(d[j]) j++; p[i]=f[j];
            while(i<=n-2&&!--d[p[i]]&&p[i]<j)
                p[i+1]=f[p[i]],i++;
        }
        for(int i=1;i<=n-2;i++) ans^=1ll*i*p[i];
    }
    void Prufer_Tree(){
        for(int i=1;i<=n-2;i++) scanf("%d",&p[i]),d[p[i]]++; p[n-1]=n;
        for(int i=1,j=1;i<n;i++,j++){
            while(d[j]) j++; f[j]=p[i];
            while(i<n&&!--d[p[i]]&&p[i]<j)
                f[p[i]]=p[i+1],i++;
        }
        for(int i=1;i<n;i++) ans^=1ll*i*f[i];
    }
    int main(){
        scanf("%d%d",&n,&tp);
        (tp==1)?Tree_Prufer():Prufer_Tree();
        printf("%lld
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    【Object-C】判断指针类型,isKindOfxxx
    【Object-C】继承,super关键字
    Echart的angularjs封装
    ng-validate
    random background
    新发现。css3控制浏览器滚动条的样式
    如何灵活利用免费开源图标字体-IcoMoon篇
    干货分享:让你分分钟学会 javascript 闭包
    webpack
    css黑魔法
  • 原文地址:https://www.cnblogs.com/zdsrs060330/p/14334965.html
Copyright © 2011-2022 走看看