• CF911F [Tree Destruction] 题解


    链接
    WC讲的第二道例题,被一分钟带过,我裂开了
    首先知道一个比较显然的东西,对于一个点,距离最长的点必定是该树的直径的其中一个端点。
    虽然这个挺显然的,不过还是证一下(老师昨天一秒带过太让人炸裂了)(这里用一个反证法吧)
    y3y28O.png
    (0,4) 为直径两端,(5,6) 为直径外两点
    (5->6) 为最长的链,那么 (1->6) 会大于 (1->4)
    那么直径就会变成 (0->6) 这与前提矛盾,所以对于 (5)(4) 是最优的选择,对 (6)(0) 是最优的选择
    然后怎么整呢,我们先把直径搞出来,对于每一个点,选择一个端点使得链最长,最后再按顺序删掉链上的所有点
    然后想一下细节(会的同志可以直接开始写了)
    对于一个点,可能有两种情况(这里使用换根法,没考虑不使用的做法)

    • 1.与上面的端点匹配
    • 2.与下面的端点匹配
      怎么找到最优的端点,还要计算长度呢,我们想到了经典的 (dep_x+dep_y-2*dep_{lca_{x,y}})
      又想到,因为其中一个端点是在链上的,所以两点的 (lca)也会在链上
      于是我们在 (dfs) 的时候,记录一个 (top) ,表示在 (dfs) 过程中上一个找到的一个在链上的点,这个点一定就是 (lca)
      这是考虑下面哪个端点,而与上面端点匹配的情况其实我们求过了
      由于是换根法,根节点就是上面的端点,所以直接用 (dep) 值就好
      啊,本人语文不好,如果看不懂也别慌,结合代码还是比较好懂得
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define ll long long
    using namespace std;
    const ll N=2e5+10;
    ll n,m,cnt,head[N],dep[N],faa[N],toper;
    ll ans,Ans,final_ans,Time;
    bool on[N];
    
    struct answer{
    	ll a,b,c;
    }A[N];
    
    struct star_platinum{
    	ll to,nxt;
    }q[N*3];
    
    inline void add(ll u,ll v){
    	q[++cnt].to=v,q[cnt].nxt=head[u],head[u]=cnt;
    	q[++cnt].to=u,q[cnt].nxt=head[v],head[v]=cnt;
    }
    
    void dfs1(ll x,ll fa){
    	if(Time==0&&dep[x]>dep[ans])ans=x;
    	if(Time==1&&dep[x]>dep[Ans])Ans=x;
    	for(ll i=head[x];i;i=q[i].nxt){
    		ll v=q[i].to;
    		if(v!=fa){
    			dep[v]=dep[x]+1;
    			dfs1(v,x);
    		}
    	}
    }
    
    void dfs2(ll x,ll fa){
    	for(ll i=head[x];i;i=q[i].nxt){
    		ll v=q[i].to;
    		if(v!=fa){
    			dfs2(v,x);
    			faa[v]=x;
    			if(on[v])on[x]=1;
    		}
    	}
    }
    
    void dfs3(ll x,ll fa,ll topf){
    	for(ll i=head[x];i;i=q[i].nxt){
    		ll v=q[i].to; 
    		if(fa!=v){
    			if(on[v])dfs3(v,x,v);
    			else dfs3(v,x,topf);
    		}
    	}
    	if(!on[x]){
    		if(dep[x]>dep[x]+dep[Ans]-(dep[topf]*2)){
    			final_ans+=dep[x];
    			A[++toper]=(answer){x,ans,x};
    		}
    		else {
    			final_ans+=dep[x]+dep[Ans]-(dep[topf]*2);
    			A[++toper]=(answer){Ans,x,x};
    		}
    	}
    }
    
    int main(){
    	scanf("%lld",&n);
    	for(ll a1,a2,i=1;i<n;i++){
    		scanf("%lld%lld",&a1,&a2);
    		add(a1,a2);
    	}
    	dfs1(1,0);
    	memset(dep,0,sizeof(dep)),Time++;
    	dfs1(ans,0);
    	on[Ans]=1;
    	dfs2(ans,0);
    	dfs3(ans,0,ans);
    	for(ll i=Ans;i!=ans;i=faa[i]){
    		final_ans+=dep[i];
    		A[++toper]=(answer){ans,i,i};
    	}
    	printf("%lld
    ",final_ans);
    	for(ll i=1;i<=toper;i++){
    		printf("%lld %lld %lld
    ",A[i].a,A[i].b,A[i].c);
    	}
    }
    
  • 相关阅读:
    剑指Offer——数组中重复的数字
    基于Google Protobuff和Mina的RPC
    Google Protocol Buffers 编码(Encoding)
    Protocol Buffers 语法指南
    Google Protocol Buffers 入门
    Google Protocol Buffers 概述 转
    Protobuf语言指南
    基于Protobuf的通讯库--Poppy简介
    log4cxx第三篇----使用多个logger
    log4CXX第二篇---配置文件(properties文件)详解
  • 原文地址:https://www.cnblogs.com/caijiLYC/p/14375280.html
Copyright © 2020-2023  润新知