【雜題】[51Nod 1367] 完美森林【貪心】
阿新 • • 發佈:2018-11-02
Description
給定一棵標號從0開始的n個節點的樹,邊有長度。
你可以刪掉一些邊使得這棵樹分裂成若干棵樹,形成一個森林。
問最少分裂成多少棵樹,使得每棵樹的直徑都不超過L
Solution
這題我已開始還想複雜了,往DP方面想
其實並不需要。
隨便給這棵樹定一個根,從葉子向上合併。
記 表示以 為根的子樹中距離它最遠的葉子到它的距離。
對於每一個節點i,將它的所有兒子p按照
排序
若最大值+次大值大於限制了,那麼刪掉連向這棵子樹的邊,次大值變為最大值,一直到合法為止。
此時重新維護這個節點的dst,就是刪剩下的最大值。
這樣就做完了…
正確性似乎很顯然…
複雜度
Code
#include <cstdio>
#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define N 500005
#define LL long long
using namespace std;
int n,m,m1,ans,fs[N],nt[2*N],dt[2*N],pr[2*N],dst[N],d[N];
void read(int &x)
{
char ch=getchar();x=0;
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
}
void link(int x,int y,int z)
{
nt[++m1]=fs[x];
dt[fs[x]=m1]=y;
pr[m1]=z;
}
void dfs(int k,int fa)
{
for(int i=fs[k];i;i=nt[i]) if(dt[i]!=fa) dfs(dt[i],k);
d[0]=0;
for(int i=fs[k];i;i=nt[i]) if(dt[i]!=fa) d[++d[0]]=pr[i]+dst[dt[i]];
sort(d+1,d+d[0]+1);
while(d[0]>1&&d[d[0]]+d[d[0]-1]>m) ans++,d[d[0]--]=0;
if(d[d[0]]>m) ans++,d[d[0]--]=0;
dst[k]=d[d[0]];
}
int main()
{
cin>>n>>m;
fo(i,1,n-1)
{
int x,y,z;
read(x),read(y),read(z);
x++,y++;
link(x,y,z),link(y,x,z);
}
dfs(1,0);
printf("%d\n",ans+1);
}