zoukankan      html  css  js  c++  java
  • 【Codeforces#596】D. Tree Factory

    Description

    传送门

    • 一个爷爷非空的节点x可以做一个操作:fa(x)=fa(fa(x))
    • 给一棵树,求如何将一条链通过最少的操作次数变成这个树,节点编号要完全一致。
    • 输出这条链初始的编号,以及操作次数,和每一次操作的节点编号。
    • n<=1e5

    Solution

    • 构造题。
    • 思路比较神奇。首先反过来,求树变成链。
    • 首先考虑最少的操作次数。从树的深度切入。
    • 最初的深度是dep,最终的深度是n,每一次最多让深度加一。
    • 那么答案的下限就是n-dep。
    • 能不能有一种方案达到这个下限呢?实际上是有的。
    • 考虑对于最长链,找到上面的最深的分叉点,在这里断开。
    • 将最长链所在的儿子接到任意一个其他的儿子上,那么深度就一定会增加1。
    • 可以证明如果没有分叉点的话一定已经是一条链了。
    • 这样O(n)构造一波就好了。从最深点往上遍历各个子树。
    • 这种构造题先找答案下限再去满足的套路要熟悉运用。
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #define maxn 100005
    using namespace std;
    
    int n,m,i,j,k,mxdep,dep[maxn],fa[maxn],cnt[maxn];
    int x,d[maxn],vis[maxn],tot,ans[maxn];
    int em,e[maxn],nx[maxn],ls[maxn];
    
    void insert(int x,int y){
    	em++; e[em]=y; nx[em]=ls[x]; ls[x]=em;
    	cnt[x]++;
    }
    
    int main(){
    	scanf("%d",&n);
    	dep[0]=1;
    	for(i=1;i<n;i++) {
    		scanf("%d",&fa[i]),dep[i]=dep[fa[i]]+1;
    		x=(dep[i]>dep[x])?i:x;
    		insert(fa[i],i);
    	}
    	mxdep=dep[x];
    	while (cnt[x]==0&&x) d[++d[0]]=x,vis[x]=1,cnt[fa[x]]--,x=fa[x];
    	for(tot=1;tot<=n-mxdep;tot++){
    		for(int &i=ls[x];i;i=nx[i]) if (!vis[e[i]]){
    			x=e[i],ans[tot]=d[d[0]];
    			break;
    		}
    		while (cnt[x]==0&&x) d[++d[0]]=x,vis[x]=1,cnt[fa[x]]--,x=fa[x];
    	}
    	printf("0 ");
    	while (d[0]) printf("%d ",d[d[0]--]);
    	printf("
    %d
    ",n-mxdep);
    	for(i=n-mxdep;i>=1;i--) printf("%d ",ans[i]);
    }
    
    
  • 相关阅读:
    C# 灵活切换开发/测试/生成环境web.config
    c# sqlserver 删除大批量数据超时
    vue 上传进度显示
    sqlserver the name is not a valid identifier error in function
    WEBAPI 设置上传文件大小
    vue 获取视频时长
    webapi 导入excel处理数据
    vscode 通过ftp发布vue到azure服务器
    C# 汉字转拼音
    静态代码扫描工具
  • 原文地址:https://www.cnblogs.com/DeepThinking/p/13090930.html
Copyright © 2011-2022 走看看