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[N],cnt,f[N],a[N];
struct qwe
{
    int ne,to;
}e[N<<1];
int read()
{
    int r=0,f=1;
    char p=getchar();
    while(p>‘9‘||p<‘0‘)
    {
        if(p==‘-‘)
            f=-1;
        p=getchar();
    }
    while(p>=‘0‘&&p<=‘9‘)
    {
        r=r*10+p-48;
        p=getchar();
    }
    return r*f;
}
void add(int u,int v)
{
    cnt++;
    e[cnt].ne=h[u];
    e[cnt].to=v;
    h[u]=cnt;
}
int dfs(int u,int fa,int w)
{
    int tot=0,r=0,l;
    for(int i=h[u];i;i=e[i].ne)
        if(e[i].to!=fa)
            r+=dfs(e[i].to,u,w);
    for(int i=h[u];i;i=e[i].ne)
        if(e[i].to!=fa)
        {
            if(f[e[i].to]+1>w)
                r++;
            else
                a[++tot]=f[e[i].to];
        }
    if(!tot)
        return r;
    sort(a+1,a+1+tot);
    l=tot;
    while(l>1&&a[l]+a[l-1]+2>w)
        l--,r++;
    f[u]=a[l]+1;
    return r;
}
bool ok(int w)
{
    memset(f,0,sizeof(f));
    // cerr<<dfs(1,0,w)<<" "<<w<<endl;
    // for(int i=1;i<=n;i++)
        // cerr<<f[i]<<" ";
    // cerr<<endl;
    return dfs(1,0,w)<=m;
}
int main()
{
    n=read(),m=read();
    for(int i=1;i<n;i++)
    {
        int x=read(),y=read();
        add(x,y),add(y,x);
    }
    int l=0,r=n-1,ans;
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(ok(mid))
            r=mid-1,ans=mid;
        else
            l=mid+1;
    }
    printf("%d\n",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/lokiii/p/9275729.html

时间: 2024-10-28 21:01:44

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

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

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

[Usaco2010 Dec]Exercise 奶牛健美操

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

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

Exercise bzoj-2097 Usaco-2010 Dec 题目大意:题目链接 注释:略. 想法:题目描述生怕你不知道这题在考二分. 关键是怎么验证?我们想到贪心的删边. 这样的策略是显然正确的. 之后树形dp的时候维护一下就行. 最后,附上丑陋的代码... ... #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #define N 10001

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

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

【树形DP/搜索】BZOJ 1827: [Usaco2010 Mar]gather 奶牛大集会

1827: [Usaco2010 Mar]gather 奶牛大集会 Time Limit: 1 Sec  Memory Limit: 64 MBSubmit: 793  Solved: 354[Submit][Status][Discuss] Description Bessie正在计划一年一度的奶牛大集会,来自全国各地的奶牛将来参加这一次集会.当然,她会选择最方便的地点来举办这次集会.每个奶牛居住在 N(1<=N<=100,000) 个农场中的一个,这些农场由N-1条道路连接,并且从任意一个

BZOJ 2101: [Usaco2010 Dec]Treasure Chest 藏宝箱( dp )

dp( l , r ) = sum( l , r ) - min( dp( l + 1 , r ) , dp( l , r - 1 ) ) 被卡空间....我们可以发现 l > r 是无意义的 , 所以可以省下一半的空间 -------------------------------------------------------------------------------- #include<cstdio> #include<cstring> #include<a

BZOJ 1827: [Usaco2010 Mar]gather 奶牛大集会( dp + dfs )

选取任意一个点为root , size[ x ] 表示以 x 为根的子树的奶牛数 , dp一次计算出size[ ] && 选 root 为集会地点的不方便程度 . 考虑集会地点由 x 点向它的子节点 son 转移 , 那么以 son 为集会地点比以 x 为集会地点要多 dist( x , son ) * ( tot - size[ x ] ) - dist( x , son ) * size[ x ] = dist( x , son ) * ( tot - 2 * size[ x ] )

BZOJ 1827: [Usaco2010 Mar]gather 奶牛大集会

Description Bessie正在计划一年一度的奶牛大集会,来自全国各地的奶牛将来参加这一次集会.当然,她会选择最方便的地点来举办这次集会.每个奶牛居住在 N(1<=N<=100,000) 个农场中的一个,这些农场由N-1条道路连接,并且从任意一个农场都能够到达另外一个农场.道路i连接农场A_i和B_i(1 <= A_i <=N; 1 <= B_i <= N),长度为L_i(1 <= L_i <= 1,000).集会可以在N个农场中的任意一个举行.另外

Codeforces 627D Preorder Test(二分+树形DP)

题意:给出一棵无根树,每个节点有一个权值,现在要让dfs序的前k个结点的最小值最大,求出这个值. 考虑二分答案,把>=答案的点标记为1,<答案的点标记为0,现在的任务时使得dfs序的前k个节点都为1. 考虑树形DP. 用dp[u]表示从节点u开始在子树中进行dfs最多可以经过多少个为1的结点,显然,若某一个子树中节点全为1,那么这个可以加到dp[u]中,此外还可以在不全为1的子树中挑选一个加到dp[u]上. 那么答案就是从标记为1的节点当做根,选两颗不完全子树和所有的完全子树(包括从父亲向上的