2017 湘潭市赛+江苏省赛H 题
题目链接:Highway
叉姐出的一个题目,超级有意思
题目意思是先给定一棵树,每条边有边权,然后要重新建n-1条边,新边的边权等于原来两点之间的距离,问说怎么建边使得总边权和最大,求最大的边权和
很巧妙的一个题目,最最朴素的做法就是处理出任意两点之间的距离,然后排序求一个最大生成树,但是复杂度太高了.
于是我们可以发现到对于原有的这棵树,它的直径肯定是要作为一条边加进去的,然后对于直径上的任意点,距离它最远的肯定是直径的两个端点之一,(反证一下就可以发现),我们用dis1[u]表示u点到直径一个端点的距离,dis2[u]表示u到另一个端点的距离.于是u要添加到新的树里时,贡献是max(dis1[u],dis2[u]) .
对于不在这个直径上的点,我们分析一下,也可以发现也是如此.于是这个问题的关键就是求树的直径了,两遍dfs即可(我比较鬼畜,做了4次).
通过这道题可以记住一个结论,在一棵树上,对于任一点,距离他最远的一定是直径的两个端点之一.
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#define LONG long long
const int INF=0x3f3f3f3f;
const LONG MOD=1e9+ 7;
const double PI=acos(-1.0);
#define clrI(x) memset(x,-1,sizeof(x))
#define clr0(x) memset(x,0,sizeof x)
#define clr1(x) memset(x,INF,sizeof x)
#define clr2(x) memset(x,-INF,sizeof x)
#define EPS 1e-10
#define lson l , mid , rt<< 1
#define rson mid + 1 ,r , (rt<<1)+1
#define root 1, m , 1
const int MAXN = 1e5 + 1000 ;
struct Edge
{
int u , to ;
int next ;
LONG w ;
}edge[MAXN*2 ] ;
int head[MAXN] ;
LONG dis[MAXN] ;
int tot = 0 ;
int p1 , p2 ;
LONG ans = 0 ;
LONG maxn = 0 ;
void Init()
{
clrI(head) ;
tot = 0 ;
ans = 0 ;
}
void Add_edge(int u , int v , LONG w)
{
edge[++tot].u = u ;
edge[tot].to = v ;
edge[tot].w = w ;
edge[tot].next = head[u] ;
head[u] = tot ;
}
void dfs1(int pre , int u )
{
for(int i = head[u] ; i != -1 ; i =edge[i].next)
{
int v = edge[i].to ;
if(pre == v)
continue ;
dis[v] = dis[u] + edge[i].w ;
if(dis[v] > maxn )
{
maxn = dis[v] ;
p1 = v ;
}
dfs1(u , v ) ;
}
}
void dfs2(int pre , int u )
{
for(int i = head[u] ; i != -1 ; i = edge[i].next)
{
int v = edge[i].to ;
if(v == pre)continue ;
dis[v] = dis[u] + edge[i].w ;
if(dis[v] >maxn)
{
maxn = dis[v] ;
p2 = v ;
}
dfs2(u , v) ;
}
}
LONG dis1 [MAXN] , dis2[MAXN] ;
void Get_dis1(int pre ,int u )
{
for(int i = head[u] ; i != -1 ; i =edge[i].next)
{
int v= edge[i].to ;
if(pre == v) continue ;
dis1[v] = dis1[u] + edge[i].w ;
Get_dis1(u , v) ;
}
}
void Get_dis2(int pre ,int u )
{
for(int i = head[u] ; i != -1 ; i =edge[i].next)
{
int v = edge[i].to ;
if(pre == v) continue ;
dis2[v] = dis2[u] + edge[i].w ;
Get_dis2(u , v) ;
}
}
int main()
{
int n ;
while(cin >> n)
{
Init() ;
int u , v ;
LONG w ;
for(int i= 1 ; i< n ; ++i)
{
scanf("%d%d%I64d",&u ,& v , &w) ;
Add_edge(u , v , w ) ;
Add_edge(v , u , w ) ;
}
dis[1] = 0 ;
maxn = 0 ;
dfs1(-1 , 1) ;
//
maxn =0 ;
dis[p1] = 0 ;
dfs2(-1 , p1) ;
ans += dis[p2] ;
dis1[p1] = 0 ;
Get_dis1(-1 , p1) ;
dis2[p2] = 0 ;
Get_dis2(-1 , p2) ;
for(int i = 1 ; i <= n ;++i)
{
if(i == p1 || i == p2)continue ;
ans += max(dis1[i] ,dis2[i]) ;
}
cout<return 0 ;
}