P5021 赛道修建

Posted qyj060604

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P5021 赛道修建相关的知识,希望对你有一定的参考价值。

P5021 赛道修建

填坑

死磕成功

仔细回想,二分答案还是很明显的

接下来是如何判断的问题

技术图片

就以样例为例子好了

我的目的是贪心选出越多长度大于mid的路径

首先,对于一条道路,如果它的长度大于等于mid,那么我们直接让sum++,直接删除这条边即可

事实上,对于以u为根的子树,经过u的路径有两种情况:

1.儿子->儿子

技术图片

如图,这条选中的红色路径把1当作中介,增加了一个答案

2.儿子->父亲

技术图片

如图,红色路径即为所求

然后我们就开始了贪心策略

首先,对于节点u,我们先获取所有u的儿子v能上传的路径

如果一个v的路径已经>=mid,直接sum++

接着,把其他<mid的儿子上传的路径丢入multiset中

每次取出一个最小值p,分两种情况:

1.能找到一条>=(mid-p)的路径:两条路径删除,sum++

2.找不到:能上传给u父亲的最长路径l变为max(l,p)

对于每个节点,都开一个multiset

这样,我在luogu就被卡常了

还有一个优化,就是把二分上界r设为树的直径

可以优化1.5s

代码:

#include<bits/stdc++.h>
using namespace std;
#define il inline 
typedef long long ll;
#define re register
const int N=50005;
int n,m; 
int hed[N],tal[N<<1],nxt[N<<1],cnt=0;
ll val[N<<1];
ll l=1,r=0,mid;
ll ans=-1;
ll dis[N];
int sum;
il ll llmax(ll x,ll y)
    return x>y?x:y;

il void addege(int x,int y,ll z)
    cnt++;
    tal[cnt]=y;
    val[cnt]=z;
    nxt[cnt]=hed[x];
    hed[x]=cnt;

il ll dfs(int u,int fa)
    multiset<ll> s;
    for(re int i=hed[u];i;i=nxt[i])
        int v=tal[i];
        if(v==fa) continue;
        ll value=val[i]+dfs(v,u);
        if(value>=mid)
            sum++;
        
        else
            s.insert(value);
        
    
    ll l=0;
    while(!s.empty())
        ll p=*s.begin();
        s.erase(s.begin());
        multiset<ll>::iterator it=s.lower_bound(mid-p);
        if(it!=s.end())
            s.erase(it);
            sum++;
        
        else
            l=llmax(l,p);
        
    
    return l;

il bool check()
    sum=0;
    dfs(1,1);
    return sum>=m;

il void Dfs(int u,int fa)
    for(re int i=hed[u];i;i=nxt[i])
        int v=tal[i];
        if(v==fa) continue;
        dis[v]=dis[u]+val[i];
        Dfs(v,u);
    

il void cal()
    memset(dis,0,sizeof(dis));
    int pos=1;
    Dfs(pos,pos);
    for(re int i=2;i<=n;i++)
        if(dis[i]>dis[pos]) pos=i;
    
    memset(dis,0,sizeof(dis));
    Dfs(pos,pos);
    for(re int i=1;i<=n;i++)
        if(dis[i]>dis[pos]) pos=i;
    
    r=dis[pos];
    //cout<<r<<endl;

int main()
    scanf("%d%d",&n,&m);
    for(re int i=1;i<n;i++)
        int x,y;
        ll z;
        scanf("%d%d%lld",&x,&y,&z);
        addege(x,y,z);
        addege(y,x,z); 
     
    cal();
    while(l<=r)
        mid=(l+r)/2ll;
        if(check()) ans=mid,l=mid+1;
        else r=mid-1;
    
    printf("%lld\\n",ans);
    return 0;

 

以上是关于P5021 赛道修建的主要内容,如果未能解决你的问题,请参考以下文章

P5021 赛道修建

P5021 赛道修建

赛道修建(树上贪心+multiset)

赛道修建

noip2018luogu5021赛道修建

赛道修建