• CF1131F Asya And Kittens(Kruskal重构树,启发式合并)


    这题难度1700,我感觉又小了……

    这题虽然没几个人是用kruskal重构树的思想做的,但是我是,所以我就放了个kruskal重构树的标签。

    题目链接:CF原网

    题目大意:有一个长为 $n$ 的排列,一开始每个数都是一个独立的联通块。有 $n-1$ 次操作,每次要求 $x_i$ 和 $y_i$ 所在的联通块相邻,然后把这两个联通块合并。求一个合法的排列使得所有操作合法。保证有解。

    $1le nle 1.5 imes 10^5$。


    这题我想了想,就想到了kruskal重构树。(smg?)

    kruskal重构树实际上是保证了对于原图的任意一个联通导出子图,如果其中的边都满足“最小”“最大”这类限制,那么在重构树上必有一棵子树满足包含的叶子结点有且仅有导出子图的点。

    那么这题也类似,对于时间小的操作涉及到的点都在一个子树上。

    那就直接kruskal重构树好了。最后答案是这个重构树的只包含叶子编号的前序遍历。(后序遍历也行)

    时间复杂度 $O(nlog n)$。

    代码短的惊人。

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=300030;
    #define FOR(i,a,b) for(int i=(a);i<=(b);i++)
    inline int read(){
        char ch=getchar();int x=0,f=0;
        while(ch<'0' || ch>'9') f|=ch=='-',ch=getchar();
        while(ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
        return f?-x:x;
    }
    int n,cnt,ls[maxn],rs[maxn],fa[maxn];
    int getfa(int x){
        return x==fa[x]?x:fa[x]=getfa(fa[x]);
    }
    void dfs(int x){
        if(ls[x]) dfs(ls[x]);
        if(x<=n) printf("%d ",x);
        if(rs[x]) dfs(rs[x]);
    }
    int main(){
        n=cnt=read();
        FOR(i,1,2*n) fa[i]=i;
        FOR(i,1,n-1){
            int x=read(),y=read();
            int u=getfa(x),v=getfa(y);
            ls[++cnt]=u;rs[cnt]=v;
            fa[u]=fa[v]=cnt;
        }
        dfs(cnt);
    }
    View Code
  • 相关阅读:
    社区检测算法--Infomap
    correlation matrices 相关矩阵
    多分类评估指标
    juniper修改用户密码
    zabbix4.4监控mysql状态
    高并发linux内核参数优化
    用脚本监控windows tcp的连接数
    使用typeperf监控系统资源
    rsync同步时报错
    windows jenkins编译报错处理
  • 原文地址:https://www.cnblogs.com/1000Suns/p/10424807.html
Copyright © 2020-2023  润新知