[bzoj2097][Usaco2010 Dec]Exercise 奶牛健美操_贪心_树形dp_二分

Exercise bzoj-2097 Usaco-2010 Dec

题目大意题目链接

注释:略。



想法:题目描述生怕你不知道这题在考二分。

关键是怎么验证?我们想到贪心的删边。

这样的策略是显然正确的。

之后树形dp的时候维护一下就行。

最后,附上丑陋的代码... ...

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 100010
using namespace std;
inline char nc() {static char *p1,*p2,buf[100000]; return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;}
int rd() {int x=0; char c=nc(); while(!isdigit(c)) c=nc(); while(isdigit(c)) x=(x<<3)+(x<<1)+(c^48),c=nc(); return x;}
int to[N<<1],nxt[N<<1],head[N],tot;
int cnt,max_dis[N],a[N];
inline void add(int x,int y)
{
	to[++tot]=y;
	nxt[tot]=head[x];
	head[x]=tot;
}
inline bool cmp(int x,int y) {return x>y;}
void dfs(int pos,int fa,int limit)
{
	bool flag=false;
	max_dis[pos]=0;
	for(int i=head[pos];i;i=nxt[i])
	{
		if(to[i]==fa) continue;
		flag=true;
		dfs(to[i],pos,limit);
		max_dis[pos]=max(max_dis[pos],max_dis[to[i]]+1);
	}
	if(!flag) {max_dis[pos]=0; return;}
	a[0]=0;
	for(int i=head[pos];i;i=nxt[i])
	{
		if(to[i]==fa) continue;
		a[++a[0]]=max_dis[to[i]]+1;
	}
	sort(a+1,a+a[0]+1,cmp);
	for(int i=1;i<a[0];i++)
	{
		if(a[i]+a[i+1]>limit) cnt++,a[i]=0;
	}
	if(a[a[0]]>limit) cnt++,a[a[0]]=0;
	sort(a+1,a+a[0]+1,cmp);
	max_dis[pos]=a[1];
}
int n,m;
int calc(int limit)
{
	cnt=0;
	dfs(1,0,limit);
	return cnt;
}
int find()
{
	int l=0,r=n-1,ans=0;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(calc(mid)<=m) ans=mid,r=mid-1;
		else l=mid+1;
	}
	return ans;
}
int main()
{
	n=rd(),m=rd();
	int x,y;
	for(int i=1;i<n;i++)
	{
		x=rd(),y=rd();
		add(x,y),add(y,x);
	}
	printf("%d\n",find());
}

小结:有意思...这种题发现直接上东西很艰难,有时候贪心可以适当地在我们的考虑范围之内。

原文地址:https://www.cnblogs.com/ShuraK/p/9557627.html

时间: 2024-10-11 23:58:20

[bzoj2097][Usaco2010 Dec]Exercise 奶牛健美操_贪心_树形dp_二分的相关文章

[Usaco2010 Dec]Exercise 奶牛健美操

[Usaco2010 Dec]Exercise 奶牛健美操 题目 Farmer John为了保持奶牛们的健康,让可怜的奶牛们不停在牧场之间 的小路上奔跑.这些奶牛的路径集合可以被表示成一个点集和一些连接 两个顶点的双向路,使得每对点之间恰好有一条简单路径.简单的说来, 这些点的布局就是一棵树,且每条边等长,都为1. 对于给定的一个奶牛路径集合,精明的奶牛们会计算出任意点对路径的最大值, 我们称之为这个路径集合的直径.如果直径太大,奶牛们就会拒绝锻炼. Farmer John把每个点标记为1..V

【bzoj2097】[Usaco2010 Dec]Exercise 奶牛健美操 二分+贪心

题目描述 Farmer John为了保持奶牛们的健康,让可怜的奶牛们不停在牧场之间 的小路上奔跑.这些奶牛的路径集合可以被表示成一个点集和一些连接 两个顶点的双向路,使得每对点之间恰好有一条简单路径.简单的说来, 这些点的布局就是一棵树,且每条边等长,都为1. 对于给定的一个奶牛路径集合,精明的奶牛们会计算出任意点对路径的最大值, 我们称之为这个路径集合的直径.如果直径太大,奶牛们就会拒绝锻炼. Farmer John把每个点标记为1..V (2 <= V <= 100,000).为了获得更加

bzoj 2097: [Usaco2010 Dec]Exercise 奶牛健美操【二分+树形dp】

二分答案,然后dp判断是否合法 具体方法是设f[u]为u点到其子树中的最长链,每次把所有儿子的f值取出来排序,如果某两条能组合出大于mid的链就断掉f较大的一条 a是全局数组!!所以要先dfs完子树才能填a!! #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=1000005; int n,m,h

BZOJ2097[Usaco2010 Dec] 奶牛健美操

我猜我这样继续做水题会狗带 和模拟赛的题很像,贪心搞一下. 1 #include<bits/stdc++.h> 2 using namespace std; 3 int read(){ 4 int x=0,f=1;char ch=getchar(); 5 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 6 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getch

BZOJ 2097 Exercise 奶牛健美操 二分答案+树形DP+贪心

题目大意:给定一棵树,可以删掉k条边,求删掉后森林中所有树直径的最大值的最小值 最大值最小,典型的二分答案 此题我们二分树的直径,每次二分DFS一次,对于每个节点统计出所有子树删边后的dis,排序,贪心删掉最大的,直到最大的两个子树相加不会超过二分的答案为止 时间复杂度O(nlog^2n) 老子的二分居然写挂了...桑不起啊啊啊啊 #include<cstdio> #include<cstring> #include<iostream> #include<algo

[bzoj4027][HEOI2015]兔子与樱花_贪心_树形dp

兔子与樱花 bzoj-4027 HEOI-2015 题目大意:每个点有c[i]朵樱花,有一个称重m, son[i]+c[i]<=m.如果删除一个节点,这个节点的樱花或移动到它的祖先中深度最大的,且没有被删除的节点,求在满足所有点界限的情况下,最多能删除的节点数. 注释:$1\le n\le 2\cdot 10^6$,$1\le m\le 10^5$,$0\le c_i\le 1000$. 想法:开始的时候很容易想到贪心,但是这东西对不对还两说 其实仔细一想这玩意儿tm显然啊??! 我们令c[i]

[bzoj4345][POI2016]Korale_堆_贪心_线段树_dfs

bzoj4345 POI2016 Korale 题目链接:https://lydsy.com/JudgeOnline/problem.php?id=4345 数据范围:略. 题解: 由于$k$的范围问题,我们很容易想到优先队列. 至于从每个状态怎么往下一个转移就是这个题的精髓. 我们先考虑第一问: 第一问没有字典序的限制,我们把所有的数按照从小到大排序. 堆里维护二元组$(Sum, id)$表示这种选取方式的和位$Sum$,最大下标为$id$. 它可以转移到$(Sum - a_{id} + a_

3279 奶牛健美操

3279 奶牛健美操 USACO 时间限制: 2 s 空间限制: 256000 KB 题目等级 : 钻石 Diamond 题解 查看运行结果 题目描述 Description Farmer John为了保持奶牛们的健康,让可怜的奶牛们不停在牧场之间的小路上奔跑.这些奶牛的路径集合可以被表示成一个点集和一些连接两个顶点的双向路,使得每对点之间恰好有一条简单路径.简单的说来,这些点的布局就是一棵树,且每条边等长,都为1. 对于给定的一个奶牛路径集合,精明的奶牛们会计算出任意点对路径的最大值,我们称之

bzoj2101[Usaco2010 Dec]Treasure Chest 藏宝箱*

bzoj2101[Usaco2010 Dec]Treasure Chest 藏宝箱 题意: 给个序列,A与B轮流取数,谁取的数总和大谁赢.每次只能取序列两端,问A能取的数总和最大是多少.假设两人都用最优策略.序列大小≤5000 题解: dp.f[i][j][0]=max(f[i+1][j][1]+a[i],f[i][j-1][1]+a[j]),f[i][j][1]=min(f[i+1][j][0],f[i][j-1][0]). 代码: 1 #include <cstdio> 2 #includ