bzoj 2097: [Usaco2010 Dec]Exercise 奶牛健美操【二分+樹形dp】
阿新 • • 發佈:2018-07-07
ons 每次 二分答案 ise stream i++ sort cer truct
二分答案,然後dp判斷是否合法
具體方法是設f[u]為u點到其子樹中的最長鏈,每次把所有兒子的f值取出來排序,如果某兩條能組合出大於mid的鏈就斷掉f較大的一條
a是全局數組!!所以要先dfs完子樹才能填a!!
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=1000005; int n,m,h[N],cnt,f[N],a[N]; struct qwe { int ne,to; }e[N<<1]; int read() { int r=0,f=1; char p=getchar(); while(p>‘9‘||p<‘0‘) { if(p==‘-‘) f=-1; p=getchar(); } while(p>=‘0‘&&p<=‘9‘) { r=r*10+p-48; p=getchar(); } return r*f; } void add(int u,int v) { cnt++; e[cnt].ne=h[u]; e[cnt].to=v; h[u]=cnt; } int dfs(int u,int fa,int w) { int tot=0,r=0,l; for(int i=h[u];i;i=e[i].ne) if(e[i].to!=fa) r+=dfs(e[i].to,u,w); for(int i=h[u];i;i=e[i].ne) if(e[i].to!=fa) { if(f[e[i].to]+1>w) r++; else a[++tot]=f[e[i].to]; } if(!tot) return r; sort(a+1,a+1+tot); l=tot; while(l>1&&a[l]+a[l-1]+2>w) l--,r++; f[u]=a[l]+1; return r; } bool ok(int w) { memset(f,0,sizeof(f)); // cerr<<dfs(1,0,w)<<" "<<w<<endl; // for(int i=1;i<=n;i++) // cerr<<f[i]<<" "; // cerr<<endl; return dfs(1,0,w)<=m; } int main() { n=read(),m=read(); for(int i=1;i<n;i++) { int x=read(),y=read(); add(x,y),add(y,x); } int l=0,r=n-1,ans; while(l<=r) { int mid=(l+r)>>1; if(ok(mid)) r=mid-1,ans=mid; else l=mid+1; } printf("%d\n",ans); return 0; }
bzoj 2097: [Usaco2010 Dec]Exercise 奶牛健美操【二分+樹形dp】