[TJOI2017]城市

[TJOI2017]城市

洛谷题目链接

明明上课听过一模一样的题,不知道为啥第一次写错了,我还是太废了

题解

很容易想到暴力枚举每条边在枚举每个点,O(\(n^3\)),肯定会T,然后我们 想一想如何优化,在改造后直径分为两种情况。(换根dp)

  1. 直径在被删除的边的两颗子树内。
  2. 直径经过新连成的边。

两种情况很明显我们要先求出各自在子树中的直径,然后计算出两个子树中某一端点最长路的最小值加上这条边取一个maxl,然后在枚举每一条边的过程中取min{maxl}。

题解

我们需要两次dfs。

dfs1


求出直径maxl和从当前节点往子节点的最大值maxx。


dfs2


我们考虑dp的思路,设从当前节点now延伸出的最长路lmax,从now的父亲fa延伸的最大值famax

则lmax=max(maxx,famax),然后我们需要在过程中处理famax。

对于famax有两种情况。

  1. 取famax(fa)+val(fa到当前点的权值)
  2. 取当前点的兄弟节点加上val

对于第二种情况又分为两种情况。

  1. 当前点事父亲最大值路径上的点,则取父亲的次大值。

  2. 否则,取父亲的最大值。

    标程

    #include<bits/stdc++.h>
    using namespace std;
    const int MN=5e3+100;
    const int inf=0x3f3f3f3f;
    int n,maxl,ans=inf;
    int a[MN],b[MN],d[MN];
    int cnt,head[MN];
    struct node{
    	int nxt,to,w;
    }e[MN<<1];
    inline void add(int a,int b,int w){
    	e[++cnt].nxt=head[a],head[a]=cnt,e[cnt].to=b,e[cnt].w=w;
    }
    struct tree{
    	int maxx,smax,lmax,famax;
    }t[MN];
    void dfs1(int now,int pre){
    	for(int i=head[now];i;i=e[i].nxt){
    		int to=e[i].to,w=e[i].w;
    		if(to==pre)continue;
    		dfs1(to,now);
    		if(t[now].maxx<t[to].maxx+w){
    			t[now].smax=t[now].maxx;
    			t[now].maxx=t[to].maxx+w;
    		}
    		else{
    			t[now].smax=max(t[now].smax,t[to].maxx+w);
    		}
    	}
    	maxl=max(maxl,t[now].maxx+t[now].smax);
    }
    int dfs2(int now,int pre){
    	int ret=inf;
    	t[now].lmax=max(t[now].maxx,t[now].famax);
    	for(int i=head[now];i;i=e[i].nxt){
    		int to=e[i].to,w=e[i].w;
    		if(to==pre)continue;
    		if(w+t[to].maxx==t[now].maxx){
    			t[to].famax=max(t[now].famax+w,t[now].smax+w);
    		}
    		else{
    			t[to].famax=max(t[now].famax+w,t[now].maxx+w);
    		}
    	}
    	for(int i=head[now];i;i=e[i].nxt){
    		int to=e[i].to;
    		if(to==pre)continue;
    		ret=min(ret,dfs2(to,now));
    	}
    	return min(ret,t[now].lmax);
    }
    int main(){
    	freopen("city.in","r",stdin);
    	freopen("city.out","w",stdout);
    	scanf("%d",&n);
    	for(int i=1;i<n;++i){
    		scanf("%d%d%d",&a[i],&b[i],&d[i]);
    		add(a[i],b[i],d[i]),add(b[i],a[i],d[i]);
    	}
    	for(int i=1;i<n;++i){
    		memset(t,0,sizeof(t));
    		int x=a[i],y=b[i],w=d[i];
    		maxl=0;
    		dfs1(x,y),dfs1(y,x);
    		ans=min(ans,max(maxl,dfs2(x,y)+dfs2(y,x)+w));
    	}
    	printf("%d\n",ans);
    	return 0;
    }
    
posted @ 2021-08-06 17:36  fanner_rick  阅读(68)  评论(0)    收藏  举报