NC210473 二分+树形dp
xg
题意
给你一个树,根节点为1,让你切点一些边使得根节点到达不了叶子节点。
且最小化砍断的道路的最长长度,砍断的道路总和不能超过m。
思路
答案具有单调性,所以明显用二分。
f[x]为x到达不了叶子节点所需要砍断的最短总路径。
对于答案k,
若x到y的距离z大于k(x为父亲,y为儿子),则对于这一链的答案即为f[y]。
若x到y的距离小于k,则取f[y]和z的最小值。
最后判断f[1]和m的大小来判断对于答案k是否ok。
技巧:到达叶子节点,把叶子节点的f[x]搞成比较大的数。
#include <iostream> #include <cmath> #include <cstdio> #include <cstring> #include <string> #include <map> #include <iomanip> #include <algorithm> #include <queue> #include <stack> #include <set> #include <vector> // #include <bits/stdc++.h> #define fastio ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0); #define sp ' ' #define endl '\n' #define FOR(i,a,b) for( int i = a;i <= b;++i) #define bug cout<<"--------------"<<endl #define P pair<int, int> #define fi first #define se second #define pb(x) push_back(x) #define ppb() pop_back() #define mp(a,b) make_pair(a,b) #define ms(v,x) memset(v,x,sizeof(v)) #define rep(i,a,b) for(int i=a;i<=b;i++) #define repd(i,a,b) for(int i=a;i>=b;i--) #define sca3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c)) #define sca2(a,b) scanf("%d %d",&(a),&(b)) #define sca(a) scanf("%d",&(a)); #define sca3ll(a,b,c) scanf("%lld %lld %lld",&(a),&(b),&(c)) #define sca2ll(a,b) scanf("%lld %lld",&(a),&(b)) #define scall(a) scanf("%lld",&(a)); using namespace std; typedef long long ll; ll gcd(ll a,ll b){return b?gcd(b,a%b):a;} ll lcm(ll a,ll b){return a/gcd(a,b)*b;} ll powmod(ll a, ll b, ll mod){ll sum = 1;while (b) {if (b & 1) {sum = (sum * a) % mod;b--;}b /= 2;a = a * a % mod;}return sum;} const double Pi = acos(-1.0); const double epsilon = Pi/180.0; const int maxn = 1e4+10; int tot = 0; int head[maxn],ver[maxn],edge[maxn],nextt[maxn]; void add(int x,int y,int z) { ver[++tot] = y,edge[tot] = z,nextt[tot] = head[x] , head[x] = tot; } int f[maxn]; int n,m; void dfs(int x,int fa,int k) { int flag = 0; for(int i = head[x];i ; i = nextt[i]){ int y = ver[i],z = edge[i]; if(y == fa) continue; flag = 1; dfs(y,x,k); if(z > k) f[x] += f[y]; else { f[x] += min(f[y],z); } } if(flag == 0) f[x] = 1e6; } int OK(int k) { memset(f,0,sizeof(f)); dfs(1,0,k); //cout<<f[1]<<sp<<k<<endl; if(f[1] > m) return 0; return 1; } int main() { // freopen("input.txt", "r", stdin); sca2(n,m); rep(i,1,n-1){ int x,y,z; sca3(x,y,z); add(x,y,z); add(y,x,z); } int l = 1,r = 1e4; while(l <= r){ int mid = (l+r)/2; if(OK(mid) == 1){ r = mid-1; } else l = mid+1; } if(OK(l) == 0) { printf("-1\n"); } else printf("%d\n",l ); }