P12652 [KOI 2024 Round 2] 拔树游戏 绿 题解

P0. 前言

联考 T1,对着样例 3s 秒掉。

然后用 pbds 大力维护,发现 CE,调了 0.5h 才注意到 __gnu_pbds::priority_queuestd::priority_queue 写法不一样,寄。

P1. 思路

观察题目中操作到底是怎么回事。

先看操作在题面中的定义:从树的根结点一直跳权值最小的儿子,得到一条以根结点为头、以某一叶子结点为尾的链,将每一链上结点的权值传给其父亲结点,并丢弃链尾得到新树。

我们要求的就是每次操作前根节点的权值,由操作定义可知,根结点的权值一定会变为权值最小的儿子的权值,这一点比较容易发现。

暴力维护应该能做到 O(n2log⁡2n)\Omicron (n^2\log_2n)O(n2log2n),但这还不够。观察样例(图中结点上数字均为权值而非标号):

一次操作后将会变为:

令根结点为 rtrtrtrtrtrt 权值最小的儿子为 xxxxxx 权值最小的儿子为 yyy,则操作可看作 rt←x,x←yrt \gets x,x \gets yrtx,xy,原 yyy 的儿子全部变为新 xxx 的儿子。

可能仅样例并不能达意,不过不影响理解其正确性。上述操作显然只比题目中操作多了“将链外的原 yyy 的儿子变为新 xxx 的儿子”一步,显然链内原 yyy 的儿子并不被影响,而链外原 yyy 的儿子的权值必然比同深度链内原 yyy 的儿子的权值大,所以也不影响接下来取最小值的操作。

上述操作儿子的次数总和显然为 O(n)\Omicron (n)O(n) 级别,时间复杂度 O(nlog⁡2n)\Omicron (n\log_2n)O(nlog2n),实现这个的方式异常多,我用的可并堆大力维护,但实际上只要用单次操作 O(log⁡2n)\Omicron (\log_2n)O(log2n) 的数据结构来维护最小值应该都能行。

P2. 代码

代码异常抽象,不建议贺。

/*
 * @Author: M_CI
 * @Date: 25/09/02 07:33:48
 * @LastEditors: M_CI
 * @LastEditTime: 25/09/02 08:26:10
 * @Description: 大丈夫ですか?
 * My Luogu Account: M_CI (UID: 556851)
 * My CF(Codeforces) Account: M_CI
 * My Outlook Email: mci1894lh@outlook.com
 * My QQ Number: 3628261474
 * My Github Account: M-CI-TY
 * Copyright (c) 2025 by M_CI, All Rights Reserved. 
 */
#include <bits/stdc++.h>
#include <bits/extc++.h>
using namespace std;

namespace Switch_Define {
    #define Pragma 0
    #define LL 0
    #define Int128 0
    #define ChBuff 1

    #if Pragma
    #pragma GCC optimize(3,"Ofast","inline")
    #endif
    #if LL
    #define int long long
    #endif
    #if Int128
    #define int __int128
    #endif
    #if ChBuff
    #ifdef __linux__
    #define getchar getchar_unlocked
    #define putchar putchar_unlocked
    #elif _WIN32
    #define getchar _getchar_nolock
    #define putchar _putchar_nolock
    #endif
    #endif
}
using namespace Switch_Define;

namespace Define {
    #define pbds __gnu_pbds
    #define cxx __gnu_cxx
    #define Cs(t) const t
    #define Ca(t) Cs(t)&
    #define Gr(t) greater<t>
    #define Le(t) less<t>
    #define It(s) s::iterator
    #define Pa(s,t) pair<s,t>
    #define fi first
    #define se second
    #define lowbit(x) (x&-x)
    #define Fill(s,l,v) fill(s,s+l,v)
    #define DF(s,l) iota(s,s+l,1)
    #define Sort(s,l,v) stable_sort(s,s+l,v)
}
using namespace Define;

namespace OI {
    void Fstd (Ca(string) name="data",Ca(bool) In=0,bool Out=0) {
        if (In) freopen ((name+".in").c_str (),"r",stdin);
        if (Out) freopen ((name+".out").c_str (),"w",stdout);
    }
    void IOS (Ca(bool) On=0) {if (On) ios::sync_with_stdio (0),cin.tie (0),cout.tie (0);}
}
using namespace OI;

namespace IDK {
    template <typename T>
    T Akane (T x=0,T f=1,char c=getchar ()) {
        for (;!isdigit (c);(c=='-')&&(f=-f),c=getchar ());
        for (;isdigit (c);x=(x<<1)+(x<<3)+(c&15),c=getchar ());
        return x*f;
    }
    template <typename T>
    void Aoi (T x,Ca(char) c) {
        if (x<0) putchar ('-'),x=-x;
        if (x>9) Aoi (x/10,0);
        putchar (x%10^48);
        if (c) putchar (c);
    }

    const int N=3e5+2;
    int n,p[N],a[N];
    vector<int> g[N];
    pbds::priority_queue<Pa(int,int),Gr(Pa(int,int))> q[N];

    void idn () {
        Aoi (a[1],'\n');
        if (q[1].empty ()) return;
        a[1]=q[1].top ().fi;
        int x=q[1].top ().se;
        q[1].pop ();
        if (q[x].empty ()) return;
        a[x]=q[x].top ().fi;
        int y=q[x].top ().se;
        q[x].pop ();
        q[y].join (q[x]);
        q[1].push ({a[y],y});
    }
    void idk () {
        n=Akane<int> ();
        for (int i=2;i<=n;i++) p[i]=Akane<int> (),g[p[i]].emplace_back (i);
        for (int i=1;i<=n;i++) a[i]=Akane<int> ();
        for (int i=1;i<=n;i++) for (Ca(int) j: g[i]) q[i].push ({a[j],j});
        for (int i=1;i<=n;i++) idn ();
    }

    int VOICE (Ca(bool) Mt=0,int T=1) {for (T=(Mt? Akane<int> (): T);T;T--) idk ();return 0;}
}
signed main () {Fstd ("game",0,0),IOS ();return IDK::VOICE ();}

namespace Switch_Undef {
    #undef Pragma
    #undef LL
    #undef Int128
    #undef ChBuff

    #undef int
    #undef getchar
    #undef putchar
}
using namespace Switch_Undef;

namespace Undef {
    #undef pbds
    #undef cxx
    #undef Cs
    #undef Ca
    #undef Gr
    #undef Le
    #undef It
    #undef Pa
    #undef fi
    #undef se
    #undef lowbit
    #undef Fill
    #undef DF
    #undef Sort
}
using namespace Undef;

P3. 闲话

又是被虐的一天啊。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值