1 条题解

  • 0
    @ 2025-8-24 22:37:34

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar yaoxi
    **

    搬运于2025-08-24 22:37:34,当前版本为作者最后更新于2022-04-05 15:32:34,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    或许会更好的阅读体验

    题面

    题目链接

    解法

    同届的巨佬们已经都通关了 USACO,只有我还在做 Gold 组的蓝题

    可以发现确定了 s1s_1 的值以后就知道了其他的所有 ss,构造方法如下:

    $$s_i = \begin{cases} r_i ,& r_i < s_1 \\ s_1 ,& l_i \le s_1 \le r_i \\ l_i ,& s_1 < l_i \\ \end{cases} $$

    让所有 sis_i 都尽量靠近 s1s_1 显然使得 AnsAns 最小。

    而此时的 AnsAns 也很容易一遍 dfsdfs 进行 O(n)O(n) 的计算,但是复杂度 n×(r1l1)n \times (r_1 - l_1)

    思考 s1s_1 对答案的贡献,显然就是 max(0,max(li)s1,s1min(ri))\max(0, \max(l_i) - s_1, s_1 - \min(r_i)),可以预处理出 lil_irir_i 的最大值 O(1)O(1) 计算。

    但是这不是最终的答案,有可能有 vv 的祖先 uu 使得 ru<s1<lvr_u < s_1 < l_v(反之同理,即 rv<s1<lur_v < s_1 < l_u)。而此时,由于要让所有 sis_i 靠近 s1s_1,则 sus_u 的取值一定为 rur_usvs_v 的取值一定为 lvl_v,对答案的贡献就成了 lvrul_v - r_u

    而如果 sus_usvs_vs1s_1 的同侧,那么 susv|s_u - s_v| 的贡献就一定小于 s1s_1 对答案的贡献,这部分可以不用考虑。于是得出重要结论:非根节点和其非根节点的祖先对答案的贡献是固定的

    因此,不难想到可以一遍 dfsdfs 就处理出 max(lvru)max(l_v - r_u),在枚举 s1s_1 的时候可以 O(1)O(1) 加入贡献。于是复杂度变为 O(r1l1)O(r_1 - l_1)。虽然还是无法通过,但是有了不少的优化空间。

    由于一部分答案的贡献是固定的,所以我们只考虑另一部分 max(0,max(li)s1,s1min(ri))\max(0, \max(l_i) - s_1, s_1 - \min(r_i))。那么显然 s1=max(li)min(ri)2s_1 = \frac{\max(l_i) - \min(r_i)}{2} 是最优的。

    于是这题就结束了,时间复杂度 O(n)O(n),为一遍 dfsdfs 的复杂度。

    AC代码

    /**
     * @file:           T3.cpp
     * @author:         yaoxi-std
     * @url:            
    */
    // #pragma GCC optimize ("O2")
    // #pragma GCC optimize ("Ofast", "inline", "-ffast-math")
    // #pragma GCC target ("avx,sse2,sse3,sse4,mmx")
    #include <bits/stdc++.h>
    using namespace std;
    #define resetIO(x) \
        freopen(#x ".in", "r", stdin), freopen(#x ".out", "w", stdout)
    #define debug(fmt, ...) \
        fprintf(stderr, "[%s:%d] " fmt "\n", __FILE__, __LINE__, ##__VA_ARGS__)
    template <class _Tp>
    inline _Tp& read(_Tp& x) {
        bool sign = false; char ch = getchar();
        for (; !isdigit(ch); ch = getchar()) sign |= (ch == '-');
        for (x = 0; isdigit(ch); ch = getchar()) x = x * 10 + (ch ^ 48);
        return sign ? (x = -x) : x;
    }
    template <class _Tp>
    inline void write(_Tp x) {
        if (x < 0) putchar('-'), x = -x;
        if (x > 9) write(x / 10);
        putchar((x % 10) ^ 48);
    }
    bool m_be;
    using ll = long long;
    const int MAXN = 1e5 + 10;
    const int INF = 0x3f3f3f3f;
    int n, m, tp, fa[MAXN], lp[MAXN], rp[MAXN], ans[MAXN];
    vector<int> g[MAXN];
    inline void chkmin(int& x, int y) { (x > y) && (x = y); }
    inline void chkmax(int& x, int y) { (x < y) && (x = y); }
    int dfs(int u, int mxl, int mnr) {
        int ret = max({0, lp[u] - mnr, mxl - rp[u]});
        chkmax(mxl, lp[u]), chkmin(mnr, rp[u]);
        for (auto v : g[u]) chkmax(ret, dfs(v, mxl, mnr));
        return ret;
    }
    bool m_ed;
    signed main() {
        // debug("Mem %.5lfMB.", fabs(&m_ed - &m_be) / 1048576);
        int cas; read(cas), read(tp);
        while (cas--) {
            read(n), m = 0;
            for (int i = 1; i <= n; ++i) g[i].clear();
            for (int i = 2; i <= n; ++i) read(fa[i]), g[fa[i]].push_back(i);
            for (int i = 1; i <= n; ++i) read(lp[i]), read(rp[i]);
            int mxl = 0, mnr = INF;
            for (int i = 1; i <= n; ++i)
                chkmax(mxl, lp[i]), chkmin(mnr, rp[i]);
            int mn = dfs(1, 0, INF), ansp = 0, answ = INF;
            for (int i = (mxl + mnr) / 2; i <= (mxl + mnr + 1) / 2; ++i) {
                int curw = mn;
                if (i < mxl) chkmax(curw, mxl - i);
                if (i > mnr) chkmax(curw, i - mnr);
                if (curw < answ) answ = curw, ansp = i;
            }
            write(answ), putchar('\n');
            if (tp) {
                for (int i = 1; i <= n; ++i) {
                    if (lp[i] <= ansp && ansp <= rp[i])
                        ans[i] = ansp;
                    else if (ansp < lp[i])
                        ans[i] = lp[i];
                    else if (rp[i] < ansp)
                        ans[i] = rp[i];
                    write(ans[i]), putchar(" \n"[i == n]);
                }
            }
        }
        return 0;
    }
    
    • 1

    信息

    ID
    7614
    时间
    2000ms
    内存
    256MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者