• E2. Weights Division (hard version)


    题:https://codeforces.com/contest/1399/problem/E2

    题意:给定一棵树,每个边权有w值和id值,分别代表边权和将改边权降为w/2的代价(1<=id<=2),当前代价nowsum为根节点到叶子节点路径的总和,问要经过最少多少id代价能将nowsum降为<=S;

    分析:首先我们可以先把nowsum算出来,其次考虑用id=1和id=2来降nowsum;

       假设我取了x个id=1和y个id=2,那么肯定是选前x大w的id=1,和y大的id2;

       基于这样考虑,我们可以先预处理id=1和id=2move操作效益大往小的前缀和序列sum1[],sum2[];

       这样就可以枚举sum1来算sum2的位置来更新答案(nlogn)

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define pb push_back
    #define MP make_pair
    #define pil pair<int,ll>
    const int inf=0x3f3f3f3f;
    const ll INF=1e18;
    const int M=4e6+5;
    struct edge{
        int v;
        ll w;
        int id;
    };
    vector<edge>g[M];
    ll nowsum,sz[M],sum1[M],sum2[M];
    struct node{
        ll x,y,z;
        bool operator < (const node &b)const{
            return x<b.x;
        }
    };
    priority_queue<node>que,que2;
    void dfs1(int u,int fa){
        if(g[u].size()==1)
            sz[u]=1;
        for(auto it:g[u]){
            int v=it.v;
            ll w=it.w;
            if(v!=fa){
                dfs1(v,u);
                sz[u]+=sz[v];
                if(it.id==1)
                    que.push(node{(w+1)/2*sz[v],w,sz[v]});
                else
                    que2.push(node{(w+1)/2*sz[v],w,sz[v]});
                nowsum+=w*sz[v];
            }
        }
    }
    int main() {
        int T;
        scanf("%d",&T);
        while(T--){
            int n;
            ll S;
            scanf("%d%lld",&n,&S);
            nowsum=0;
            for(int i=1;i<=n;i++)
                g[i].clear(),sz[i]=0;
            while(!que.empty())
                que.pop();
            while(!que2.empty())
                que2.pop();
            for(int i=1;i<n;i++){
                int u,v,id;
                ll w;
                scanf("%d%d%lld%d",&u,&v,&w,&id);
                g[u].pb(edge{v,w,id});
                g[v].pb(edge{u,w,id});
            }
            dfs1(1,0);
            int tot1=0;
            while(que.size()>0){
                node u=que.top();
                que.pop();
                if(u.x==0)
                    break;
                sum1[++tot1]=u.x;
                u.y=u.y/2;
                u.x=(u.y+1)/2*u.z;
                que.push(u);
            }
            for(int i=1;i<=tot1;i++)
                sum1[i]+=sum1[i-1];
            int tot2=0;
            while(que2.size()>0){
                node u=que2.top();
                que2.pop();
                if(u.x==0)
                    break;
                sum2[++tot2]=u.x;
                u.y=u.y/2;
                u.x=(u.y+1)/2*u.z;
                que2.push(u);
            }
            for(int i=1;i<=tot2;i++)
                sum2[i]+=sum2[i-1];
            sum2[tot2+1]=INF;
            ll need=nowsum-S;
            int ans=inf;
            for(int i=0;i<=tot1;i++){
                ll tmp=need-sum1[i];
                int pos=lower_bound(sum2,sum2+1+tot2,tmp)-sum2;
                if(pos==tot2+1)
                    continue;
                ans=min(ans,i+2*pos);
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    NodeJS简介
    SQL学习笔记(1)
    Linux常用命令03
    Linux常用命令02
    Linux常用命令01
    Java接口和抽象类的区别
    Optional解决空指针
    JVM的内存管理机制-转载
    mysql explain详解-转载
    rabbitmq消息处理-转载
  • 原文地址:https://www.cnblogs.com/starve/p/13615938.html
Copyright © 2020-2023  润新知