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;
}

posted @ 2025-11-20 20:35  NDAKJin  阅读(5)  评论(0)    收藏  举报