Codeforces Round #661 (Div. 3) E1 E2

题目:E1. Weights Division (easy version)

题意读错了折磨的,给定一棵树,n个点n-1条边,每一条边有权重,给定一个价值S,问 v l e a v e s W ( r o o t , v ) < = S \sum_{v\in{leaves}^{W(root,v)}}<=S ,意思即根到每个叶子节点的距离路线的总和价值小于S,你每次可以操作任意一条边使其变成 w i 2 \lfloor \frac{wi}{2} \rfloor ,
问最小多少次操作使其小于S。

根节点到每个叶子节点的路线都要计算一遍,那我们可以先统计某一个节点的叶子节点个数,也就是这条路线要被走多少次,总价值就是 w i t i m e s w_i * times ,然后意思是任意选择一条边向下取整,我们可以大根堆的优先队列来解决。
直接放入价值推w[i]会掉精度,是向下取整。

#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<istream>
#include<vector>
#include<stack>
#include<set>
#include<map>
#include<algorithm>
#include<queue>
#define inf 0x3f3f3f3f
#define llinf 0x3f3f3f3f3f3f3f3f
#define MAX_len 200005*4
using namespace std;
typedef long long ll;
typedef pair<ll,ll> PP;
const int mod=1e9+7;
ll n,s,sum;
ll times[100010];
vector<PP>hh[100100];
struct cmp {
    bool operator()(PP t1,PP t2) {
        return ((t1.first-t1.first/2)*t1.second) < ((t2.first-t2.first/2)*t2.second);
    }
};
priority_queue<PP,vector<PP>,cmp>que;
void dfs(int u,int f) {
    if(hh[u].size()==1&&u!=1) {
        times[u]=1;
        return ;
    }
    for(int i=0;i<hh[u].size();i++) {
        int v=hh[u][i].first;
        if(v==f)
            continue;
        dfs(v,u);
        times[u]+=times[v];
    }
    return ;
}
void ddffss(int u,int f) {
    if(hh[u].size()==1&&u!=1) {
        return ;
    }
    for(int i=0;i<hh[u].size();i++) {
        int v=hh[u][i].first;
        if(v==f)
            continue;
        que.push(make_pair(hh[u][i].second,times[v]));
        sum+=hh[u][i].second*times[v];
        ddffss(v,u);
    }
    return ;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
       scanf("%lld %lld",&n,&s);
       sum=0;
       while(!que.empty())
        que.pop();
       for (int i=0;i<=n+1;i++)
            hh[i].clear(),times[i]=0;
       for(int i=1;i<n;i++) {
            ll u,v,val;
            scanf("%lld %lld %lld",&u,&v,&val);
            hh[u].push_back(make_pair(v,val));
            hh[v].push_back(make_pair(u,val));
       }
       dfs(1,-1);
       ddffss(1,-1);
       if(sum<=s) {
        printf("0\n");
        continue;
       }
       ll ans=0;
       while(sum>s) {
            PP temp;
            temp=que.top();
            que.pop();
            ans++;
            sum-=(temp.first-temp.first/2)*temp.second;
            que.push(make_pair(temp.first/2,temp.second));
       }
       printf("%lld\n",ans);
    }
    return 0;
}

题目:E2. Weights Division (hard version)

题意同上,就是每条边加入了需要耗费的次数,有耗费1或者2,问最小的耗费数,那么问题就是选择耗费1的边还是2,就有了贪心的策略,两个优先队列分别存,对情况进行分析判定。可见代码,写的比较繁杂,注意细节。

#include<cmath>
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<istream>
#include<vector>
#include<stack>
#include<set>
#include<map>
#include<algorithm>
#include<queue>
#define inf 0x3f3f3f3f
#define llinf 0x3f3f3f3f3f3f3f3f
#define MAX_len 200005*4
using namespace std;
typedef long long ll;
typedef pair<ll,ll> PP;
const int mod=1e9+7;
ll n,s,sum;
struct A {
    ll edgeto,edgeval,cost;
};
ll times[100010];
vector<A>hh[100100];
struct cmp {
    bool operator()(PP t1,PP t2) {
        return ((t1.first-t1.first/2)*t1.second) < ((t2.first-t2.first/2)*t2.second);
    }
};
priority_queue<PP,vector<PP>,cmp>q1,q2;
void dfs(int u,int f) {
    if(hh[u].size()==1&&u!=1) {
        times[u]=1;
        return ;
    }
    for(int i=0;i<hh[u].size();i++) {
        int v=hh[u][i].edgeto;
        if(v==f)
            continue;
        dfs(v,u);
        times[u]+=times[v];
    }
    return ;
}
void ddffss(int u,int f) {
    if(hh[u].size()==1&&u!=1) {
        return ;
    }
    for(int i=0;i<hh[u].size();i++) {
        int v=hh[u][i].edgeto;
        if(v==f)
            continue;
        if(hh[u][i].cost==1) {
            q1.push(make_pair(hh[u][i].edgeval,times[v]));
        }
        else {
            q2.push(make_pair(hh[u][i].edgeval,times[v]));
        }
        sum+=hh[u][i].edgeval*times[v];
        ddffss(v,u);
    }
    return ;
}
ll solve(ll x,ll y) {
    return ((x-x/2)*y);
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
       scanf("%lld %lld",&n,&s);
       sum=0;
       while(!q1.empty())
        q1.pop();
       while(!q2.empty())
        q2.pop();
       for (int i=0;i<=n+1;i++)
            hh[i].clear(),times[i]=0;
       for(int i=1;i<n;i++) {
            ll u,v,uu,vv;
            scanf("%lld %lld %lld %lld",&u,&v,&uu,&vv);
            A temp;
            temp.edgeto=v,temp.edgeval=uu,temp.cost=vv;
            hh[u].push_back(temp);
            temp.edgeto=u;
            hh[v].push_back(temp);
       }
       dfs(1,-1);
       ddffss(1,-1);
       if(sum<=s) {
        printf("0\n");
        continue;
       }
       ll ans=0;
       while(sum>s) {
            PP q1temp,q2temp;
            if(q1.size()==0) {
                ans+=2;
                q2temp=q2.top();
                q2.pop();
                sum-=solve(q2temp.first,q2temp.second);
                q2.push(make_pair(q2temp.first/2,q2temp.second));
                continue;
            }
            q1temp=q1.top();
            ll t1=solve(q1temp.first,q1temp.second);
            if(sum-t1<=s) {
                ans++;
                break;
            }
            if(q2.size()==0) {
                ans++;
                sum-=t1;
                q1.pop();
                q1.push(make_pair(q1temp.first/2,q1temp.second));
                continue;
            }
            q2temp=q2.top();
            ll t2=solve(q2temp.first,q2temp.second);
            if(q1.size()==1) {
                t1+=solve(q1temp.first/2,q1temp.second);
                if(t1<t2) {
                    ans+=2;
                    sum-=t2;
                    q2.pop();
                    q2.push(make_pair(q2temp.first/2,q2temp.second));
                }
                else {
                    ans++;
                    sum-=solve(q1temp.first,q1temp.second);;
                    q1.pop();
                    q1.push(make_pair(q1temp.first/2,q1temp.second));
                }
                continue;
            }
            ll t3=solve(q1temp.first/2,q1temp.second);
            q1.pop();
            ll t5=solve(q1.top().first,q1.top().second);
            if((t2>=t1+t3)&&(t2>=t1+t5)) {
                ans+=2;
                sum-=t2;
                q2.pop();
                q1.push(q1temp);
                q2.push(make_pair(q2temp.first/2,q2temp.second));
            }
            else {
                ans++;
                sum-=t1;
                q1.push(make_pair(q1temp.first/2,q1temp.second));
            }
       }
       printf("%lld\n",ans);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43958964/article/details/107856988