题解 洛谷 P3563 【[POI2013]POL-Polarization】

先考虑最小值,因为树是二分图,所以可以进行黑白染色,将其分成左右部图,让左部图向右部图连边即可构造最小值,为 \(n-1\)

对于最大值,最优情况一定是以一个点为中心,其各个子树内边的状态为要么该点能到达子树内的每个点,即外向,要么子树内的每个点能到达该点,即内向,且该点为树的重心。

可以简单的进行证明。考虑边的状态让这棵树有了两个上面描述的中心,两个中心之间的路径上一半的边指向第一个中心,一半的边指向第二个中心。发现若这条路径边的方向只指向一个中心,答案会更优,所以就将这两个中心合并为一个,同理,若存在多个中心,合并为一个会更优。因为中心的各个子树的外向个数和内向个数会乘起来贡献给答案,所以中心选取树的重心可以更好的分配外向内向的子树大小。

考虑将中心的各个子树分为外向和内向两个集合,两个集合大小越接近 \(\frac{n}{2}\) 越优。可以通过二进制拆分来优化这个多重背包问题,因为只用考虑存在性,所以也采用 \(bitset\) 来优化。

\(code:\)

#include<bits/stdc++.h>
#define maxn 500010
using namespace std;
typedef long long ll;
template<typename T> inline void read(T &x)
{
    x=0;char c=getchar();bool flag=false;
    while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    if(flag)x=-x;
}
int n,root;
ll ans;
int siz[maxn],ma[maxn],cnt[maxn];
bitset<maxn> s;
struct edge
{
    int to,nxt;
}e[maxn];
int head[maxn],edge_cnt;
void add(int from,int to)
{
    e[++edge_cnt]=(edge){to,head[from]};
    head[from]=edge_cnt;
}
void dfs(int x,int fa)
{
    siz[x]=1;
    for(int i=head[x];i;i=e[i].nxt)
    {
        int y=e[i].to;
        if(y==fa) continue;
        dfs(y,x),siz[x]+=siz[y];
        ma[x]=max(ma[x],siz[y]);
    }
    ma[x]=max(ma[x],n-siz[x]);
    if(ma[x]<ma[root]) root=x;
}
int main()
{
    read(n),ma[0]=n;
    for(int i=1;i<n;++i)
    {
        int x,y;
        read(x),read(y);
        add(x,y),add(y,x);
    }
    dfs(1,0),dfs(root,0);
    for(int i=1;i<=n;++i) ans+=siz[i]-1;
    for(int i=head[root];i;i=e[i].nxt) cnt[siz[e[i].to]]++;
    for(int i=1;i<=n;++i)
        while(cnt[i]>2)
            cnt[i]-=2,cnt[i*2]++;
    s[0]=1;
    for(int i=1;i<=n;++i)
        for(int j=1;j<=cnt[i];++j)
            s|=s<<i;
    for(int i=n/2;i;--i)
    {
        if(!s[i]) continue;
        printf("%d %lld\n",n-1,ans+(ll)i*(n-i-1));
        break;
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/lhm-/p/13399231.html