POJ - 1655 (点分治-树的重心)

Posted lis-

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ - 1655 (点分治-树的重心)相关的知识,希望对你有一定的参考价值。

题目:https://vjudge.net/contest/307753#problem/D

题意:给你一棵树,让你求出一个点,让他的最大子树的节点数尽量小

思路:最大子树节点数尽量小,一看就是树的重心, 然后随便套个原来的点分治模板即可

 

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream> 
#include<vector>
#define maxn 100005
#define mod 1e19
using namespace std;
typedef long long ll;
ll da;
vector<pair<ll,ll> > mp[maxn];//存下图 
bool vis[maxn];//标记曾经使用过的重心 
ll maxsize[maxn],dis[maxn],d[maxn];//maxsize 当前节点的最大子树 
ll siz[maxn],e[maxn];// dis 到重心的距离  d 出现过的距离 
ll n,m,rt,sum,qe;  // siz 当前节点的子树个数  e 出现的距离  rt代表当前重心 
void find(ll x,ll f)//找出重心 
    siz[x]=1;
    maxsize[x]=0;
    for(int i=0;i<mp[x].size();i++)
        pair<ll,ll> q=mp[x][i];
        if(q.first==f||vis[q.first]) continue;//vis数组标记曾经使用过的重心 
        find(q.first,x);
        siz[x]+=siz[q.first];
        maxsize[x]=max(maxsize[x],siz[q.first]); 
     
    maxsize[x]=max(maxsize[x],sum-siz[x]);//节点总数减去当前的子树数=以当前节点为根的父亲点子树数 
    if(maxsize[x]<maxsize[rt])
        rt=x;
    
    else if(maxsize[x]==maxsize[rt]&&rt>x)
        rt=x;
     

void get_dis(ll x,ll f,ll len)
    e[++qe]=len;
    for(int i=0;i<mp[x].size();i++)
        pair<ll,ll> q=mp[x][i];
        if(q.first==f||vis[q.first]) continue;
        dis[q.first]=dis[x]+len;
        get_dis(q.first,x,len+q.second);
        

ll solve(ll x,ll len)
    ll ee=0;
    qe=0;
    dis[x]=len;
    get_dis(x,0,len);
    sort(e+1,e+qe+1);
    ll l=1,r=qe;
    while(l<r)
        if(e[l]+e[r]<=m)
            ee+=r-l;
            l++;
        
        else
            r--;
        
    
    return ee;

void divide(ll x)
    da+=solve(x,0);
    vis[x]=1;
    for(int i=0;i<mp[x].size();i++)
        pair<ll,ll> q=mp[x][i];
        if(vis[q.first]) continue;
        da-=solve(q.first,q.second);
        sum=siz[q.first];
        rt=0;
        maxsize[rt]=mod;
        find(q.first,x);
        divide(rt);
    

void init()
    da=0;
    for(int i=0;i<=n;i++) mp[i].clear();
    for(int i=0;i<=n;i++) vis[i]=0;
 
int main()
    int t;
    scanf("%d",&t);
    while(t--)
    
        scanf("%lld",&n);
        ll a,b,c;
        init();
        for(int i=0;i<n-1;i++)
            scanf("%lld%lld",&a,&b);
            mp[a].push_back(make_pair(b,c));
            mp[b].push_back(make_pair(a,c));
        
        sum=n;//当前节点数 
        rt=0;
        maxsize[0]=mod;//置初值 
        find(1,0);
        //divide(rt);
        printf("%lld %lld\n",rt,maxsize[rt]);
    
 

 

以上是关于POJ - 1655 (点分治-树的重心)的主要内容,如果未能解决你的问题,请参考以下文章

POJ 1655 BalanceAct 3107 Godfather (树的重心)(树形DP)

POJ 1655 Balancing Act (求树的重心)树形DP(经典)

poj 1655 找树的重心

poj 1655 树的重心

poj1655 树的重心 树形dp

poj1655 Balancing Act(找树的重心)