題解 洛谷 P3563 【[POI2013]POL-Polarization】
阿新 • • 發佈:2020-07-30
先考慮最小值,因為樹是二分圖,所以可以進行黑白染色,將其分成左右部圖,讓左部圖向右部圖連邊即可構造最小值,為 \(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; }