zoukankan      html  css  js  c++  java
  • 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);
    	}
    }
    
  • 相关阅读:
    1104 Sum of Number Segments (20 分)(数学问题)
    1092 To Buy or Not to Buy (20 分)(hash散列)
    1082 Read Number in Chinese (25 分)(字符串处理)【背】
    1105 Spiral Matrix (25 分)(模拟)
    初识网络安全及搭建网站(内网)
    HTML5开发者需要了解的技巧和工具汇总(转)
    native+web开发模式之web前端经验分享
    移动平台3G手机网站前端开发布局技巧汇总(转)
    Asp.net 中图片存储数据库以及页面读取显示通用方法详解附源码下载
    使用H3Viewer来查看VS2010的帮助文档
  • 原文地址:https://www.cnblogs.com/caijiLYC/p/14375280.html
Copyright © 2011-2022 走看看