HDU3586-Information Disturbing
HDU3586-Information Disturbing
题目大意
给你一棵树,你可以花费 \(w_i\) 去切断一条边。你的目标是切断每个叶子节点到根节点 \(1\) 的联系。要求在切断的总花费不大于 \(m\) 的条件下,最小化切断边的花费 \(w\) 的最大值。 无论如何都做不到,则输出 \(-1\) 。
题解
考虑二分答案,难点在于怎么check。
对于一个结点,要么切断连接它和父节点的边,要么子树下的叶子节点全部被切断的总花费。所以从叶子节点开始拓扑 \(bfs\) ,可以算出到根节点 \(1\) 为止的最小花费。\(check\) 时,只有小于 \(mid\) 的边才可以被切断。
如果二分结果 \(\geq 1000\) ,则无解输出 \(-1\) 。
#include<bits/stdc++.h>
#define ios ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define umap unordered_map
#define endl '\n'
using namespace std;
using i128 = __int128;
const int mod =1e9+7;
template <typename T>void read(T&x){
x=0;int f = 1;
char c=getchar();
for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+(c^48);
x*=f;
}
template <typename T>void print(T x) {
if (x < 0) { putchar('-'); x = -x; }
if (x > 9) print(x / 10);
putchar(x % 10 + '0');
}
#define int long long
const int N=500005;
const int M=2000005;
int n,m;
vector<pair<int,int> > G[2000];
vector<int> fa(2000);
vector<int> deg(2000);
vector<int> ww(2000);
vector<int> minn(2000,1e18);
void dfs1(int u,int f)
{
fa[u]=f;
for(auto [v,w]: G[u])
{
if(v==f) ww[u]=w;
if(fa[v]!=v) continue;
dfs1(v,u);
}
}
inline void solve()
{
for(int i=1;i<=n;i++) fa[i]=i,deg[i]=0,minn[i]=0,G[i].clear();
for(int i=1;i<n;i++)
{
int u,v,w;
cin>>u>>v>>w;
G[u].push_back({v,w});
G[v].push_back({u,w});
deg[u]++,deg[v]++;
}
dfs1(1,0);
int l=1,r=1005;
while(l<r)
{
int mid=l+r>>1;
queue<int> q;
vector<int> _deg=deg;
for(int i=1;i<=n;i++) minn[i]=0;
for(int i=2;i<=n;i++)
{
if(_deg[i]==1)
{
q.push(i);
_deg[i]=0;
minn[i]=1e10;
}
}
while(!q.empty())
{
int u=q.front();q.pop();
if(ww[u]<=mid) minn[fa[u]]+=min(ww[u],minn[u]);
else
{
minn[fa[u]]+=minn[u];
}
if(--_deg[fa[u]]==1&&fa[u]!=1)
{
q.push(fa[u]);
}
}
if(minn[1]<=m)
{
r=mid;
}
else
{
l=mid+1;
}
}
if(r>=1000) cout<<-1<<endl;
else cout<<r<<endl;
}
signed main()
{
// ios;
int T=1;
// cin>>T;
for(;T;)
{
cin>>n>>m;
if(n==0&&m==0) break;
solve();
}
return 0;
}

浙公网安备 33010602011771号