51nod 1737 配对 && Codeforces 700B Connecting Universities【树的重心】

1737 配对

基准时间限制:1 秒空间限制:131072 KB 分值: 40

 

给出一棵n个点的树,将这n个点两两配对,求所有可行的方案中配对两点间的距离的总和最大为多少。

Input

一个数n(1<=n<=100,000,n保证为偶数)

接下来n-1行每行三个数x,y,z表示有一条长度为z的边连接x和y(0<=z<=1,000,000,000)

Output

一个数表示答案

Input示例

6

1 2 1

1 3 1

1 4 1

3 5 1

4 6 1

Output示例

7

//配对方案为(1,2)(3,4)(5,6)


【思路】结果其实就是树的重心到其余各点的距离和。

那么我们先给出树的重心的定义:树的重心也叫树的质心。对于一棵树n个节点的无根树,找到一个点,使得把树变成以该点为根的有根树时,最大子树的结点树最小。换句话说,删除这个点后最大连通块(一定是树)的结点数最小————from baidu

由此我们设temp[i]为以i作为根节点,其最大子树的节点个数。设num[i]为以某一个点x作为根节点时,节点i所有子树的节点个数和。

设点i的子节点集合为v,那么num[i]=Σnum[v],而i的父亲节点及以上的顶点个数和记为num[fa]=(n-(num[i]+1)),那么temp[i]=max(max(num[v],num[fa]))。

具体求解用一个DFS即可,找到重心后以它为root再来一次DFS就可以计算出距离和了。

#include <cstdio>
#include <vector>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define mst(a,b) memset((a),(b),sizeof(a))
#define rush() int T;scanf("%d",&T);while(T--)

typedef long long ll;
const int maxn = 100005;
const int mod = 100000000;
const int INF = 0x3f3f3f;
const double eps = 1e-9;

struct node
{
    int u,v,w,next;
} e[maxn*2];

int n;
int cnt,root,Min;
ll ans;
int vis[maxn];
int head[maxn];
int num[maxn];

void init()
{
    cnt=0;
    mst(vis,0);
    mst(num,0);
    mst(head,-1);
}

void add(int u,int v,int w)
{
    e[cnt].v=v;
    e[cnt].w=w;
    e[cnt].next=head[u];
    head[u]=cnt++;
}

int dfs_zhongxin(int u,int pre)
{
    if(num[u]==0)
    {
        num[u]=1;
        for(int i=head[u];~i;i=e[i].next)
        {
            int v=e[i].v;
            if(v==pre) continue;
            num[u]+=dfs_zhongxin(v,u);
        }
        int temp=0;
        for(int i=head[u];~i;i=e[i].next)
        {
            int v=e[i].v;
            temp=max(temp,num[v]);
        }
        temp=max(temp,n-num[u]);
        if(temp<Min)
        {
            Min=temp;
            root=u;
        }
    }
    return num[u];
}


void dfs(int u,ll sum)
{
    ans+=sum;
    vis[u]=1;
    for(int i=head[u];~i;i=e[i].next)
    {
        int v=e[i].v;
        int w=e[i].w;
        if(vis[v]==0)
        {
            dfs(v,sum+w);
        }
    }
}

int main()
{
    int x,y,w;
    while(~scanf("%d",&n))
    {
        init();
        for(int i=1; i<n; i++)
        {
            scanf("%d%d%d",&x,&y,&w);
            add(x,y,w);
            add(y,x,w);
        }
        root=-1;
        Min=INF;
        ans=0;
        dfs_zhongxin(1,-1);
        dfs(root,0);
        printf("%I64d\n",ans);
    }
    return 0;
}

B. Connecting Universities


time limit per test  3 seconds

memory limit per test      256 megabytes


Treeland is acountry in which there are n towns connectedby n - 1 two-way roadsuch that it's possible to get from any town to any other town.

In Treeland there are 2k universitieswhich are located in different towns.

Recently, thepresident signed the decree to connect universities by high-speed network.TheMinistry of Education understood the decree in its own way and decided that itwas enough to connect each university with another one by using a cable.Formally, the decree will be done!

To have themaximum sum in the budget, the Ministry decided to divide universities intopairs so that the total length of the required cable will be maximum. In otherwords, the total distance between universities in k pairs should be as large as possible.

Help the Ministry to find the maximum total distance. Of course, each university shouldbe present in only one pair. Consider that all roads have the same length whichis equal to 1.

Input

The first lineof the input contains two integers n and k (2 ≤ n ≤ 200 000, 1 ≤ k ≤ n / 2) — thenumber of towns in Treeland and the number of university pairs. Consider thattowns are numbered from 1 to n.

The second linecontains 2k distinctintegers u1, u2, ..., u2k (1 ≤ ui ≤ n) — indices of towns in which universities are located.

The next n - 1 line contains the description of roads. Each line contains the pair ofintegers xj and yj (1 ≤ xj, yj ≤ n), which means that the j-th roadconnects towns xj and yj. All of them are two-way roads. You can move from any town to any otherusing only these roads.

Output

Print the maximum possible sum ofdistances in the division of universities into k pairs.

Examples

Input

7 2
1 5 6 2
1 3
3 2
4 5
3 7
4 3
4 6

Output

6

Input

9 3
3 2 1 6 5 9
8 9
3 2
2 7
3 4
7 6
4 5
2 1
2 8

Output

9

Note

The figure below shows one of possibledivision into pairs in the first test. If you connect universities number 1 and 6 (marked in red)and universities number 2 and 5 (marked in blue) by using the cable, the total distance will equal 6 which will be the maximum sum in this example.

 


【思路】这道题跟上面的类似,就是找到树的重心,不过稍微有点不同的是,这道题找中心所考虑的的点只有建有学校的点,找到重心后算距离和也只需要算那些有学校的点。


#include <cstdio>
#include <vector>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
#define mst(a,b) memset((a),(b),sizeof(a))
#define rush() int T;scanf("%d",&T);while(T--)

typedef long long ll;
const int maxn = 200005;
const int mod = 100000000;
const int INF = 0x3f3f3f;
const double eps = 1e-9;

struct node
{
    int u,v,w,next;
}e[maxn*2];

int n,k;
ll ans;
int cnt,root,Min;
int vis[maxn];
int num[maxn];
int head[maxn];

void init()
{
    cnt=0;
    mst(vis,0);
    mst(num,0);
    mst(head,-1);
}

void add(int u,int v,int w)
{
    e[cnt].v=v;
    e[cnt].w=w;
    e[cnt].next=head[u];
    head[u]=cnt++;
}

int dfs_zhongxin(int u,int pre)
{
    if(num[u]==0)
    {
        if(vis[u]==1)
            num[u]=1;
        for(int i=head[u];~i;i=e[i].next)
        {
            int v=e[i].v;
            if(v==pre) continue;
            num[u]+=dfs_zhongxin(v,u);
        }
        int temp=0;
        for(int i=head[u];~i;i=e[i].next)
        {
            int v=e[i].v;
            temp=max(temp,num[v]);
        }
        temp=max(temp,k*2-num[u]);
        if(temp<Min)
        {
            Min=temp;
            root=u;
        }
    }
    return num[u];
}

void dfs(int u,int pre,int sum)
{
    if(vis[u]==1)
        ans+=sum;
    for(int i=head[u];~i;i=e[i].next)
    {
        int v=e[i].v;
        if(v==pre) continue;
        int w=e[i].w;
        dfs(v,u,sum+w);
    }
}

int main()
{
    int x,y;
    while(~scanf("%d%d",&n,&k))
    {
        init();
        for(int i=0;i<2*k;i++)
        {
            scanf("%d",&x);
            vis[x]=1;
        }
        for(int i=1;i<n;i++)
        {
            scanf("%d%d",&x,&y);
            add(x,y,1);
            add(y,x,1);
        }
        root=-1;
        Min=INF;
        dfs_zhongxin(1,-1);
        ans=0;
        dfs(root,-1,0);
        printf("%I64d\n",ans);
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值