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);
    	}
    }
    
  • 相关阅读:
    golang 使用 iota
    Event Sourcing Pattern 事件源模式
    Win10桌面预览版14316更新内容大全
    腾信微信公众号初步开发应用
    微信支付:H5吊起支付API,不显示“确认支付、输入密码”界面
    开发者了解---微信公众号(服务号、订阅号、企业号)的区别
    X240 Win10企业版 14279版本 电池标尺白底问题
    Go项目的目录结构
    Command and Query Responsibility Segregation (CQRS) Pattern 命令和查询职责分离(CQRS)模式
    .NET环境下基于RBAC的访问控制
  • 原文地址:https://www.cnblogs.com/caijiLYC/p/14375280.html
Copyright © 2011-2022 走看看