题解 洛谷 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;
}
posted @ 2020-04-04 14:46  lhm_liu  阅读(353)  评论(0编辑  收藏  举报