没有证明的贪心就是乱搞
解析
把标签写在题面上的一道题…
显然要二分答案然后看能不能分出来m个
关键策略是每个结点内部尽可能的多匹配的前提下,给父亲传一个最大的
这不纪念品分组?
然后我就无脑的敲了个双指针的贪心上去
然后就WA掉了qwq
(由于带限制的点太多这竟然还有80)
纪念品分组的贪心只保证了尽可能多匹配
却不能保证剩下一个最大的
一个简单的例子是较小值和次大值匹配,把最大值传上去
然而如果按照从小往大扫,每一个贪心的想与尽可能小的匹配,这样就能保证贪心的正确性了
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=50050;
const int mod=998244353;
inline ll read() {ll x=0,f=1;char c=getchar();while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f;
}
int n,m;
struct node{int to,nxt,w;
}p[N<<1];
int fi[N],cnt;
inline void addline(int x,int y,int w){p[++cnt]=(node){y,fi[x],w};fi[x]=cnt;return;
}
int len[N],tot,now,ans;
vector<int>v[N];
bool ok[N];
void dfs(int x,int f){v[x].clear();for(int i=fi[x];~i;i=p[i].nxt){int to=p[i].to;if(to==f) continue;dfs(to,x);if(len[to]+p[i].w>=now) ans++;else v[x].push_back(len[to]+p[i].w);}sort(v[x].begin(),v[x].end());int l=0,r=v[x].size()-1;for(int i=0;i<=r;i++) ok[i]=1;for(int i=0;i<=r;i++){if(!ok[i]) continue;int st=0,ed=r+1;while(st<ed){int mid=(st+ed)>>1;if(v[x][mid]+v[x][i]>=now) ed=mid;else st=mid+1;}while(st<=r&&(!ok[st]||st==i)) st++;if(st<=r){ok[st]=ok[i]=0;//printf("x=%d %d %d\n",x)ans++;}}len[x]=0;for(int i=v[x].size()-1;i>=0;i--){if(ok[i]){len[x]=v[x][i];break;}}return;
}
bool check(int k){ans=0;now=k;dfs(1,0);return ans>=m;
}
signed main() {#ifndef ONLINE_JUDGEfreopen("a.in","r",stdin);freopen("a.out","w",stdout);#endifmemset(fi,-1,sizeof(fi));cnt=-1;n=read();m=read();for(int i=1;i<n;i++){int x=read(),y=read(),w=read();addline(x,y,w);addline(y,x,w);tot+=w;}
// printf("%d\n",check(38));int st=0,ed=tot;while(st<ed){int mid=(st+ed+1)>>1;if(check(mid)) st=mid;else ed=mid-1;}printf("%d\n",st);return 0;
}