换根DP例题2 CF708C

换根DP例题2

例题2

给你一棵 n n n 个结点的无向树,你可以执行最多一次的边替换操作,即从树中删除任意一条边,但不删除顶点,然后再往树内加一条边,且不添加新结点,操作完后该图必须是树。

对于每个结点,你需要判断是否能通过执行至多一次操作,使得它们变成树的重心。

树的重心指的是,如果我们把树的重心从树中移除,那么分裂出的连通分量的大小必须不超过 n 2 \frac{n}{2} 2n

数据范围: 2 ≤ n ≤ 4 × 1 0 5 2\le n\le 4\times10^5 2n4×105

题解

思绪

这题需要对每个结点都判断是否至多一次操作后能成为重心,这个特征使得我们可以往换根 DP 上思考。

接下来思考操作的最优性,若树根不是重心,只需从一棵大小大于 n 2 \frac{n}{2} 2n 的子树内找到一棵大小为 x x x 的子树,将其摘出并连接到根上即可。

设那个大于 n 2 \frac{n}{2} 2n 的子树大小为 s s s,那么 x x x 应该满足 { s − x ≤ n 2 x ≤ n 2 \begin{cases}s-x\le\frac{n}{2}\\ x\le \frac{n}{2}\end{cases} {sx2nx2n,整理得 s − n 2 < x < n 2 s-\frac{n}{2}<x<\frac{n}{2} s2n<x<2n,于是得到了关于每次操作所摘子树的约束。

接下来应该思考,一棵树的答案如何组成?再细致一点就是,那个大小大于 n 2 \frac{n}{2} 2n 的子树的根是谁?如何取得 x x x

任意选一个结点 u u u 作为根,设其儿子为 v 1 , v 2 , ⋯   , v k v_1,v_2,\cdots,v_k v1,v2,,vk,设 s i z e u size_u sizeu 表示以 u u u 为根的子树大小。

  1. 如果 s i z e v 1 , s i z e v 2 , ⋯   , s i z e v k size_{v_1},size_{v_2},\cdots,size_{v_k} sizev1,sizev2,,sizevk 均不超过 n 2 \frac{n}{2} 2n,那么 u u u 需要 0 0 0 次操作后会变为重心。

  2. 如果 s i z e v i > n 2 size_{v_i}>\frac{n}{2} sizevi>2n,那么要想让 u u u 变成重心,只能去操作 v i v_i vi 子树内的点。

    我们希望操作完之后 v i v_i vi 尽量小, x x x 尽量大,所以我们只需要选择 v i v_i vi 内的一个最大的且不大于 n 2 \frac{n}{2} 2n 的子树删去即可。如果删去之后 v i v_i vi 的子树大小仍大于 n 2 \frac{n}{2} 2n,那么说明该点经过一次操作无法成为重心。

如果以其他结点为根会比较复杂,我们可以令重心 G G G 为根,然后如何找某个子树里的最大且不超过 n 2 \frac{n}{2} 2n 的子树呢,可以参考下面这个过程:

不妨假设当前结点是 u u u,我们有一个 set<PII> 存的是不包含当前 u u u 的子树,但包含 u u u 的父亲方向的子树内的所有小于 n 2 \frac{n}{2} 2n 的子树大小。

  1. 计算当前结点答案,因为当前结点子树必然小于 n 2 \frac{n}{2} 2n,所以我们需要从 set 里找一个最大值,然后看一下 n − s i z e u − max ⁡ n-size_u-\max nsizeumax 是否大于 n 2 \frac{n}{2} 2n
  2. 为下次 DFS 做准备,把当前结点向下的所有子树的 { s i z e v , v } \{size_v,v\} {sizev,v} 塞入 s e t set set 里面,因为子树必然大小都不超过 n 2 \frac{n}{2} 2n,所以直接塞入即可。
  3. 开始 DFS,当遍历到 v v v 时,我们先从 set 中删去 { s i z e v , v } \{size_v,v\} {sizev,v},**如果以 f a v fa_v fav 为根的子树大小( n − s i z e v n-size_v nsizev)不超过 n 2 \frac{n}{2} 2n 的话,我们也需要将这个子树大小插入 s e t set set 里。**此时的 set 更新完毕,所以直接进行 DFS(v, u)。

代码

#include <bits/stdc++.h>
using namespace std;
//#pragma GCC optimize(2)
#define int long long
#define endl '\n'
#define PII pair<int,int>
#define INF 1e18


void slove () {
    int n;
    cin >> n;

    vector <int> g[n + 1];
    for (int i = 1; i <= n - 1; i ++) {
        int u, v;
        cin >> u >> v;

        g[u].push_back(v);
        g[v].push_back(u);
    }

    int G = 0;
    vector <int> siz(n + 1, 0);
    function <void (int, int)> dfs =[&] (int u, int fa) {
        siz[u] = 1;
        for (auto v : g[u]) {
            if (v == fa) continue;
            dfs (v, u);
            siz[u] += siz[v];
        }
    };
    dfs(1, 0);

    for (int i = 1; i <= n; i++) {
        bool found = true;
        if (n - siz[i] > n/2) continue;
        for (auto v : g[i]) {
            if (siz[v] > siz[i]) continue;
            if (siz[v] > n/2) found = false;
        }
        if (found) G = i;
    }

    dfs (G, 0);
    vector <int> ans (n + 1, 0);
    set <PII> t;

    function <void(int, int)> dfs2 =[&] (int u, int fa) {
        bool found = true;

        int maxn = 0;
        for (auto i = t.rbegin(); i != t.rend() ;i--) {
            if (i->second != u) {
                if (n - i->first - siz[u] > n/2) found = false;
                break;
            }
        }
        if (found) ans[u] = 1;

        for (auto v : g[u]) {
            if (v == fa) continue;
            t.insert(PII{siz[v], v});
        }

        for (auto v : g[u]) {
            if (v == fa) continue;
            t.erase(PII{siz[v], v});
            if (n - siz[v] <= n/2) t.insert(PII{n - siz[v], u});

            dfs2 (v, u);
            t.insert(PII{siz[v], v});
            if (n - siz[v] <= n/2) t.erase(PII{n - siz[v], u});
        }
    };

    dfs2 (G, 0);
    for (int i = 1; i <= n; i++) cout << ans[i] << ' ';
    cout << endl;
}

signed main () {
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    slove();
}

代码


【电动汽车充电站有序充电调度的分散式优化】基于蒙特卡诺和拉格朗日的电动汽车优化调度(分时电价调度)(Matlab代码实现)内容概要:本文介绍了基于蒙特卡洛和拉格朗日方法的电动汽车充电站有序充电调度优化方案,重点在于采用分散式优化策略应对分时电价机制下的充电需求管理。通过构建数学模型,结合不确定性因素如用户充电行为和电网负荷波动,利用蒙特卡洛模拟生成大量场景,并运用拉格朗日松弛法对复杂问题进行分解求解,从而实现全局最优或近似最优的充电调度计划。该方法有效降低了电网峰值负荷压力,提升了充电站运营效率与经济效益,同时兼顾用户充电便利性。 适合人群:具备一定电力系统、优化算法和Matlab编程基础的高校研究生、科研人员及从事智能电网、电动汽车相关领域的工程技术人员。 使用场景及目标:①应用于电动汽车充电站的日常运营管理,优化充电负荷分布;②服务于城市智能交通系统规划,提升电网与交通系统的协同水平;③作为学术研究案例,用于验证分散式优化算法在复杂能源系统中的有效性。 阅读建议:建议读者结合Matlab代码实现部分,深入理解蒙特卡洛模拟与拉格朗日松弛法的具体实施步骤,重点关注场景生成、约束处理与迭代收敛过程,以便在实际项目中灵活应用与改进。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

louisdlee.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值