Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 262144/262144 K (Java/Others)
Total Submission(s): 1215    Accepted Submission(s): 416

Problem Description
Avin has two trees which are not connected. He asks you to add an edge between them to make them connected while minimizing the function j. He is happy with only the function value.
 
Input
The first line contains a number v. The input is guaranteed to contain exactly two trees.
 
Output
Just print the minimum function value.
 
Sample Input
3 1 2
 
Sample Output
4
 
Source
 
Recommend
liuyiding
题意:给定两棵树,然后让你加上一条边使得成为一棵树,并且新树上的所有的任意两点的距离最小。

析:首先根据题意应该能够知道连接两棵树的重心才是最小的距离,树的重心查找方式就是枚举每个点,然后计算去年该点剩下的连通分量中点的数量最多的需要最少,只需要一个DFS就可以解决。有了重心后,可以直接连一条边,然后再计算距离,距离计算可以枚举所有边的贡献,该边的贡献就是该边左点的点数乘以该边右边的点数。

代码如下:

#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <cstdio>
#include <string>
#include <cstdlib>
#include <cmath>
#include <iostream>
#include <cstring>
#include <set>
#include <queue>
#include <algorithm>
#include <vector>
#include <map>
#include <cctype>
#include <cmath>
#include <stack>
#include <sstream>
#include <list>
#include <assert.h>
#include <bitset>
#include <numeric>
#define debug() puts("++++")
#define print(x) cout<<(x)<<endl
// #define gcd(a, b) __gcd(a, b)
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define fi first
#define se second
#define pb push_back
#define sqr(x) ((x)*(x))
#define ms(a,b) memset(a, b, sizeof a)
// #define sz size()
#define be begin()
#define ed end()
#define pu push_up
#define pd push_down
#define cl clear()
#define lowbit(x) -x&x
#define all 1,n,1
#define FOR(i,n,x)  for(int i = (x); i < (n); ++i)
#define freopenr freopen("in.in", "r", stdin)
#define freopenw freopen("out.out", "w", stdout)
using namespace std;

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int, int> P;
const int INF = 0x3f3f3f3f;
const LL LNF = 1e17;
const double inf = 1e20;
const double PI = acos(-1.0);
const double eps = 1e-8;
const int maxn = 1e5 + 7;
const int maxm = 2000000 + 7;
const LL mod = 1e9 + 7;
const int dr[] = {-1, 1, 0, 0, 1, 1, -1, -1};
const int dc[] = {0, 0, 1, -1, 1, -1, 1, -1};
int n, m;

inline bool is_in(int r, int c) {
  return r >= 0 && r < n && c >= 0 && c < m;
}
inline int readInt(){
  int x;  cin >> x;  return x;
}

struct Edge{
  int to, next;
};

int head[maxn];
int cnt;
Edge edges[maxn<<1];
int f[maxn], sz[maxn];
int p[maxn];

inline int Find(int x){
  return x == p[x] ? x : p[x] = Find(p[x]);
}

void add_edge(int u, int v){
  edges[cnt].to = v;
  edges[cnt].next = head[u];
  head[u] = cnt++;
}

void dfs(int u, int fa, int num, int &rt){
  sz[u] = 1;
  f[u] = 0;
  for(int i = head[u]; ~i; i = edges[i].next){
    int v = edges[i].to;
    if(v != fa){
      dfs(v, u, num, rt);
      sz[u] += sz[v];
      f[u] = max(f[u], sz[v]);
    }
  }
  f[u] = max(f[u], num - sz[u]);
  if(f[u] < f[rt])  rt = u;
}

int dp[maxn];

LL dfs(int u, int fa){
  dp[u] = 1;
  LL ans = 0;
  for(int i = head[u]; ~i; i = edges[i].next){
    int v = edges[i].to;
    if(v != fa){
      ans += dfs(v, u);
      dp[u] += dp[v];
      ans += dp[v] * 1LL * (n - dp[v]);
    }
  }
  return ans;
}
map<int, int> mp;

int main(){
  while(scanf("%d", &n) == 1){
    cnt = 0;  ms(head, -1);
    for(int i = 0; i <= n; ++i)  p[i] = i;
    for(int i = 2; i < n; ++i){
      int x, y;  scanf("%d %d", &x, &y);
      add_edge(x, y);
      add_edge(y, x);
      x = Find(x);
      y = Find(y);
      if(x != y)  p[y] = x;
    }

    mp.cl;
    for(int i = 1; i <= n; ++i)  ++mp[Find(i)];
    ms(f, INF);
    auto it = mp.be;
    int rt1 = 0, rt2 = 0;
    dfs(it->fi, -1, it->se, rt1);
    ++it;
    dfs(it->fi, -1, it->se, rt2);
    add_edge(rt1, rt2);
    add_edge(rt2, rt1);

    print(dfs(1, -1));
  }
  return 0;
}

  

相关文章: