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


    P5021 赛道修建

    分析:

    很明显要二分一个值。

    对于一条赛道与一个点u的关系,可以分成三种情况:

    1.完全在一棵u的子树内。   2.一半在子树内,一半在子树外     3. 经过u,连向子树内的另一条链

    对于第一种情况,直接在递归下去的时候就计入贡献。

    对于第二三种情况,开一个multiset,遇到不合法的值就放入multiset中。

    每次回溯的时候,先将子树内可以两两合并的合并了,不能两两合并的,取一个最大值留给其父亲节点去匹配。

    multiset有很多细节:

    1. erase既可以删除一个值,也可以删除一个位置!!

    2. 删除的顺序很重要,千万不要出现删掉一个点后,又指向那个点,这时候会指向空,从而导致崩溃。

    #include<bits/stdc++.h>
    using namespace std;
    #define ri register int
    #define N 50005
    int head[N],nex[N<<1],to[N<<1],tot=0,w[N<<1],n,m,mid,ans;
    void add(int a,int b,int ww) {  tot++; to[tot]=b; nex[tot]=head[a]; head[a]=tot; w[tot]=ww; }
    multiset<int> st[N];
    multiset<int>::iterator it;//!!!在外面定义才能遍历完 
    int dfs(int u,int ff)
    {
        st[u].clear();
        int val;
        for(ri i=head[u];i;i=nex[i]){
            int v=to[i];
            if(v==ff) continue;
            val=dfs(v,u)+w[i];
            if(val>=mid) ans++;//子树内的链直接满足情况,就ans++ 
            else st[u].insert(val);
        }
        int mx=0;
        while(!st[u].empty()){
            if(st[u].size()==1) return mx=max(mx,*st[u].begin());
            it=st[u].lower_bound(mid-*st[u].begin());//找到对应的位置 
            if(st[u].begin()==it && st[u].count(*it)==1) it++;//如果找到自己,就跳过
            //如果不存在对应的值与它配对,说明它太小了,就删掉这种值 
            if(it==st[u].end()) mx=max(mx,*st[u].begin()),st[u].erase(*st[u].begin());//注意删除的是值!! 
            else{//否则就将其与对应位置配对 
                ans++;
                //注意顺序:先删it,否则删去begin后,若it指向begin,那么it将指向空,会爆掉 
                st[u].erase(it);
                st[u].erase(st[u].begin());//这里删除的是头位置,而不应该是值,因为值有多个,位置只有一个 
            }
        }
        return mx;
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        int sum=0,a,b,ww;
        for(ri i=1;i<=n-1;++i) scanf("%d%d%d",&a,&b,&ww),add(a,b,ww),add(b,a,ww),sum+=ww;
        int l=0,r=sum+1,anss=0;
        while(l<r){
            mid=(l+r)>>1; ans=0;
            dfs(1,0);
            if(ans<m) r=mid;
            else l=mid+1,anss=mid;
        }
        printf("%d
    ",anss);
    }
    View Code
  • 相关阅读:
    PHP把下划线分隔命名的字符串与驼峰式命名互转
    Cocos2d-JS/Ajax用Protobuf与NodeJS/Java通信
    gulp 实现 js、css,img 合并和压缩
    转:入门Webpack,看这篇就够了
    微信开发教程:用户账号绑定到微信公众号的方法分享
    C#RSA算法实现+如何将公钥为XML格式转为PEM格式,给object-C使用
    php使用openssl进行Rsa长数据加密(117)解密(128) 和 DES 加密解密
    Windows下将nginx安装为服务运行
    转载:Centos7 从零编译配置Memcached
    转载:Centos7 从零编译Nginx+PHP+MySql 二
  • 原文地址:https://www.cnblogs.com/mowanying/p/11838324.html
Copyright © 2020-2023  润新知