zoukankan      html  css  js  c++  java
  • 题解 洛谷 P6142 【[USACO20FEB]Delegation P】

    赛道修建类似,先对(k)进行二分,将最值问题转化为判定问题。

    在判定一个(k)是否合法时,贪心去考虑,一个节点下面的若干条链在合并时,一条链肯定和另一条使它合并后恰好满足长度限制的链合并最优。因此我们用(multiset)来进行维护,一条长度为(len)的链,去查询第一条长度大于等于(k-len)的链,若找不到,即不合法。

    再考虑到一个非根节点在合并链时,是可以有一条链无法合并,其它链两两配对,那么剩下那个链就往上继续寻找配对即可,但根节点肯定是要两两配对。

    所以在合并时,可以增加一个长度为(0)的链,来使非根节点的链数量为奇数,使根节点的链数量为偶数,方便一些细节的处理。

    实现就看代码吧。

    (code:)

    #include<bits/stdc++.h>
    #define maxn 200010
    using namespace std;
    typedef multiset<int>::iterator mul;
    template<typename T> inline void read(T &x)
    {
        x=0;char c=getchar();bool flag=false;
        while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        if(flag)x=-x;
    }
    int n;
    bool flag;
    int f[maxn];
    struct edge
    {
        int to,nxt;
    }e[maxn];
    int head[maxn],edge_cnt=1;
    void add(int from,int to)
    {
        e[++edge_cnt]=(edge){to,head[from]};
        head[from]=edge_cnt;
    }
    void dfs(int x,int fa,int len)
    {
    	if(!flag) return;
        multiset<int> s;
    	for(int i=head[x];i;i=e[i].nxt)
    	{
    		int y=e[i].to;
    		if(y==fa) continue;
    		dfs(y,x,len);
    		s.insert(f[y]+1);
    	}
        int size=s.size();
        bool tag=false;
        if((x==1&&size&1)||(x!=1&&!(size&1))) s.insert(0);
        while(!s.empty())
        {
            if(!flag) break;
            int l1;
            mul t1=s.begin(),t2;
            l1=*t1,s.erase(t1),t2=s.lower_bound(len-l1);
            if(x==1)
            {
                if(t2==s.end())
                {
                    flag=false;
                    break;
                }
                s.erase(t2);
            }
            else
            {
                if(t2==s.end()&&tag)
                {
                    flag=false;
                    break;
                }
                if(t2==s.end()&&!tag) f[x]=l1,tag=true;
                if(t2!=s.end()) s.erase(t2);
            }
        }
    }
    bool check(int x)
    {
        flag=true,memset(f,0,sizeof(f)),dfs(1,0,x);
        return flag;
    }
    int main()
    {
        read(n);
        for(int i=1;i<n;++i)
        {
            int a,b;
            read(a),read(b);
            add(a,b),add(b,a);
        }
        int l=1,r=n-1,ans=1;
        while(l<=r)
        {
            int mid=(l+r)>>1;
            if(check(mid)) ans=mid,l=mid+1;
            else r=mid-1;
        }
        printf("%d",ans);
        return 0;
    }
    
  • 相关阅读:
    又到黄金季节,该跳槽吗?怎么跳?
    分布式事务 6 个技术方案
    15 个 MyBatis 技巧,赶紧收藏吧!
    你的工资被倒挂了吗
    终于知道 Java agent 怎么重写字节码了
    每天的工作,你腻了吗?
    10 分钟轻松学会 Jackson 反序列化自动适配子类
    SpringMVC异步处理的 5 种方式
    Linux Cron 定时任务
    人类简史、软件架构和中台
  • 原文地址:https://www.cnblogs.com/lhm-/p/12631812.html
Copyright © 2011-2022 走看看