Codeforces Round #661 (Div. 3) E2. Weights Division (hard version)

链接

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

题意

树形图上,每次选一条边使其边权 w w w 变为 ⌊ w 2 ⌋ \lfloor\frac{w}{2}\rfloor 2w

每条边的花费为 1 1 1 2 2 2

求让 ∑ v ∈ l e a v e s w ( r o o t , v ) ≤ s \sum\limits_{v\in leaves}{w(root,v)}\le s vleavesw(root,v)s的最小花费

思路

DFS 求出每条边经过多少路径并不断对其操作记录每次对答案的贡献

用两个数组分别存 花费 1 1 1 和花费 2 2 2 的贡献,从大到小排序,求前缀和,因为某条边的贡献前一次操作必大于后一次操作,所以排序后是合法的

从左向右遍历花费 1 1 1 的数组,并从右向左枚举花费 2 2 2 的数组找到最小的满足要求的下标,取最小值为答案

因为数组可能为空,或者可能最小值为只取一种花费的情况,所以可以在数组开头加个 0 0 0,表示该种花费不操作

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pb push_back
#define mp make_pair
#define fi first
#define se second
typedef pair<int,int> pii;
typedef vector<int> vi;
//head
const int N=1e5+5;
int n,s,sum;
struct E {
    int v,w,c;
    E(){}
    E(int v,int w,int c):v(v),w(w),c(c){}
};
vector<E> G[N];
vi p,q;
bool cmp(int a,int b) {
    return a>b;
}
int dfs(int u,int fa,int w,int c) {
    int sz=0;
    for(auto x:G[u]) {
        int v=x.v,w=x.w,c=x.c;
        if(v==fa) continue;
        sz+=dfs(v,u,w,c);
    }
    if(!sz) sz=1;
    sum+=sz*w;
    if(c==1) while(w*sz-w/2*sz) p.pb(w*sz-w/2*sz),w/=2;
    else while(w*sz-w/2*sz) q.pb(w*sz-w/2*sz),w/=2;
    return sz;
}
void solve() {
    p.clear(),q.clear();
    p.pb(0),q.pb(0);
    dfs(1,0,0,0);
    sort(p.begin()+1,p.end(),cmp);
    sort(q.begin()+1,q.end(),cmp);
    for(int i=2;i<(int)p.size();i++) p[i]+=p[i-1];
    for(int i=2;i<(int)q.size();i++) q[i]+=q[i-1];
    int res=0x3f3f3f3f;
    sum-=s;
    for(int i=0,j=q.size()-1;i<(int)p.size();i++) {
        bool f=false;
        while(j>=0&&p[i]+q[j]>=sum) j--,f=true;
        if(f) j++;
        if(p[i]+q[j]>=sum) res=min(res,i+j*2);
    }
    printf("%lld\n",res);
}
signed main() {
    int T;
    scanf("%lld",&T);
    while(T--) {
        scanf("%lld%lld",&n,&s);
        sum=0;
        for(int i=1;i<=n;i++) G[i].clear();
        for(int i=1;i<n;i++) {
            int u,v,w,c;
            scanf("%lld%lld%lld%lld",&u,&v,&w,&c);
            G[u].pb(E(v,w,c));
            G[v].pb(E(u,w,c));
        }
        solve();
    }
    return 0;
}
1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看REAdMe.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。 1、资源项目源码均已通过严格测试验证,保证能够正常运行; 2、项目问题、技术讨论,可以给博主私信或留言,博主看到后会第一时间与您进行沟通; 3、本项目比较适合计算机领域相关的毕业设计课题、课程作业等使用,尤其对于人工智能、计算机科学与技术等相关专业,更为适合; 4、下载使用后,可先查看READme.md或论文文件(如有),本项目仅用作交流学习参考,请切勿用于商业用途。 5、资源来自互联网采集,如有侵权,私聊博主删除。 6、可私信博主看论文后选择购买源代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值