神奇的check函数,
任世界千变万化,我check永远是check
1>land
一棵树,求砍cut刀以后,
cut+1棵数中,直径最大值 最小是多少
//因为cut刀怎么砍与直径最大值有关,不好控制, //所以我们通过枚举最大的直径,然后去dfs砍枝 //然后,让我们来见证,这个神奇的二分剪法 #include<cstdio> #include<cstdlib> #include<vector> using namespace std; int n,cut; const int N=4e5+3; int d[N],sz[N]; vector <int> g[N]; int mid,sum; int check(int nw,int f) { int l_mn=mid,r_mx=0,cnt=0; for(int i=0;i<sz[nw];i++) { int u=g[nw][i]; if(u==f) continue; int len=check(u,nw)+1; if(len>mid) sum++; else if(len>(mid>>1)) cnt++,l_mn=min(l_mn,len); else if(len>0) r_mx=max(r_mx,len); } if(cnt) { sum+=cnt; if(l_mn+r_mx<=mid) { sum--; return l_mn; } } return r_mx; } int main() { scanf("%d%d",&n,&cut); int u,v; for(int i=1;i<n;i++) scanf("%d%d",&u,&v),g[u].push_back(v),g[v].push_back(u); for(int i=1;i<=n;i++) sz[i]=g[i].size() ; if(cut+1>=n) printf("0\n"); else { int l=0,r=n,ans=0; while(l<=r) { mid=(l+r)>>1;//>cut就是这个解太优了,要把解变差一点,就是把ans的范围往右边调整 sum=0,check(1,0);
if(sum>cut) l=mid+1; else ans=mid,r=mid-1;//重点注意这个地方的写法!!!! . //求的是cut刀,最小ans是多少, //但是有可能此最小ans的时候,最小砍cut-1刀, //所以写的时候,就是<=cut的时候,都更新答案,但是大于不行 } printf("%d\n",ans); } return 0; }
2>派
3>皇帝的烦恼
原文:https://www.cnblogs.com/xwww666666/p/11609217.html