首页 > 代码库 > Codeforces Round #392 (div.2) E:Broken Tree

Codeforces Round #392 (div.2) E:Broken Tree

orz一开始想不画图做这个题(然后脑袋就炸了,思维能力有待提高)

我的做法是动态规划+贪心+构造

首先把题目给的树变成一个可行的情况,同时weight最小

这个可以通过动态规划解决 dp[x]表示以x为结点的子树,它的最小weight是多少

接着我们就只需要考虑每条边增加多少就可以了,这里可以用贪心的做法

ddfs(int x, int fa, int v) 这里v是表示给x结点最大多少增量,然后慢慢加就可以,返回没用掉的增量

 

其实这个做法有点奇怪,应该有更简便的做法(我觉得可以直接贪心做)

#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
const int maxn = 4*111111;
const long long Give = 2e18;
struct Edge
{
    int from, to;
    long long w, v;
};
vector<Edge> edges;
vector<int> G[maxn];
long long dp[maxn], delta[maxn], dd[maxn], Fail;
void addedge(int from, int to, int w, int v)
{
    edges.push_back((Edge){from, to, w, v});
    edges.push_back((Edge){to, from, w, v});
    int m = edges.size();
    G[from].push_back(m-2);
    G[to].push_back(m-1);
}

void dfs(int x, int fa)
{
    dp[x] = 0;
    for(int i = 0; i < G[x].size(); i++)
    {
        Edge &e = edges[G[x][i]];
        if(e.to == fa) continue;
        dfs(e.to, x);
        if(e.v - dp[e.to] < 0) Fail = 1;
        delta[G[x][i]] = min(e.w-1, e.v - dp[e.to]);
        dp[x] += (e.w - delta[G[x][i]] + dp[e.to]);
    }
}

long long ddfs(int x, int fa, long long v)
{
    long long ans = 0;
    //cout<<x<<endl<<endl;
    for(int i = 0; i < G[x].size(); i++)
    {
        Edge &e = edges[G[x][i]];
        if(e.to == fa) continue;
        long long t = min(v, delta[G[x][i]]);
        ans += t; v -= t;
        dd[G[x][i]] = delta[G[x][i]] - t;
        dd[G[x][i]^1] = dd[G[x][i]];
        long long dt = ddfs(e.to, x, min(v, e.v-dd[G[x][i]]-dp[e.to]));
        ans += dt; v -= dt;
    }
    return ans;
}

int n, x, y, w, v;
int main()
{
    //freopen("a.txt", "r", stdin);
    cin.sync_with_stdio(false);
    cin>>n;
    for(int i = 1; i < n; i++)
    {
        cin>>x>>y>>w>>v;
        addedge(x, y, w, v);
    }
    dfs(1, 1);
    //for(int i = 1; i <= n; i++) cout<<i<<" "<<dp[i]<<endl;
    if(Fail) cout<<"-1";
    else
    {
        ddfs(1, 1, Give);
        cout<<n<<endl;
        for(int i = 0; i < 2*(n-1); i += 2)
        {
            Edge &e = edges[i];
            cout<<e.from<<" "<<e.to<<" "<<e.w - dd[i]<<" "<<e.v - dd[i]<<endl;
        }
    }
}

 

Codeforces Round #392 (div.2) E:Broken Tree