P1131 [ZJOI2007] 时态同步

P1131 [ZJOI2007] 时态同步

题意:

有一颗树,有一个点是激发器,从这个点开始可以产生一个激励电流,通过导线传向每一个它所连接的节点,经过一个边的花费为w[i],你有一个道具,每用一次可以让一个边的花费+1,问最少操作多少次,使得到所有叶子节点的花费一样

题解:

我们只能延长边权,不能缩短边权
我们可以从最深的子树开始,把所有子节点调整到同一深度,再到上一层,调整上一层的树枝
为什么这样最优?因为这样我们会往后调整靠根节点的树枝,而调整靠根节点的树枝,会让其下所有叶子节点同时移动,这样可以做到花最小的费用实现最多的事
可以简单理解成让更多人的人上车后再发车
在这里插入图片描述
这样可以保证代价最少
每次调整代价就是根节点的深度减去 其儿子节点的深度 再减 边权

代码:

// Problem: P1131 [ZJOI2007] 时态同步
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P1131
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// By Jozky

#include <bits/stdc++.h>
#include <unordered_map>
#define debug(a, b) printf("%s = %d\n", a, b);
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
clock_t startTime, endTime;
//Fe~Jozky
const ll INF_ll= 1e18;
const int INF_int= 0x3f3f3f3f;
void read(){};
template <typename _Tp, typename... _Tps> void read(_Tp& x, _Tps&... Ar)
{
    x= 0;
    char c= getchar();
    bool flag= 0;
    while (c < '0' || c > '9')
        flag|= (c == '-'), c= getchar();
    while (c >= '0' && c <= '9')
        x= (x << 3) + (x << 1) + (c ^ 48), c= getchar();
    if (flag)
        x= -x;
    read(Ar...);
}
template <typename T> inline void write(T x)
{
    if (x < 0) {
        x= ~(x - 1);
        putchar('-');
    }
    if (x > 9)
        write(x / 10);
    putchar(x % 10 + '0');
}
void rd_test()
{
#ifdef ONLINE_JUDGE
#else
    startTime= clock();
    freopen("data.in", "r", stdin);
#endif
}
void Time_test()
{
#ifdef ONLINE_JUDGE
#else
    endTime= clock();
    printf("\nRun Time:%lfs\n", (double)(endTime - startTime) / CLOCKS_PER_SEC);
#endif
}
const int maxn= 1e6 + 9;
vector<PII> vec[maxn];
ll ans= 0;
ll dis[maxn];
void dfs(int u, int fa)
{
    int maxx= 0;
    for (auto it : vec[u]) {
        int v= it.first;
        int w= it.second;
        if (v == fa)
            continue;
        dfs(v, u);
        //根节点到叶子节点的最大距离
        dis[u]= max(dis[u], dis[v] + w);
    }

    for (auto it : vec[u]) {
        int v= it.first;
        int w= it.second;
        if (v == fa)
            continue;
        //每次调整的代价
        ans+= dis[u] - (dis[v] + w);
    }
}
int main()
{
    //rd_test();
    int n, s;
    read(n, s);
    for (int i= 1; i < n; i++) {
        int u, v, w;
        read(u, v, w);
        vec[u].push_back({v, w});
        vec[v].push_back({u, w});
    }
    dfs(s, 0);
    cout << ans << endl;
    //Time_test();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值