P0. 前言
联考 T1,对着样例 3s 秒掉。
然后用 pbds 大力维护,发现 CE,调了 0.5h 才注意到 __gnu_pbds::priority_queue 和 std::priority_queue 写法不一样,寄。
P1. 思路
观察题目中操作到底是怎么回事。
先看操作在题面中的定义:从树的根结点一直跳权值最小的儿子,得到一条以根结点为头、以某一叶子结点为尾的链,将每一链上结点的权值传给其父亲结点,并丢弃链尾得到新树。
我们要求的就是每次操作前根节点的权值,由操作定义可知,根结点的权值一定会变为权值最小的儿子的权值,这一点比较容易发现。
暴力维护应该能做到 O(n2log2n)\Omicron (n^2\log_2n)O(n2log2n),但这还不够。观察样例(图中结点上数字均为权值而非标号):

一次操作后将会变为:

令根结点为 rtrtrt,rtrtrt 权值最小的儿子为 xxx,xxx 权值最小的儿子为 yyy,则操作可看作 rt←x,x←yrt \gets x,x \gets yrt←x,x←y,原 yyy 的儿子全部变为新 xxx 的儿子。
可能仅样例并不能达意,不过不影响理解其正确性。上述操作显然只比题目中操作多了“将链外的原 yyy 的儿子变为新 xxx 的儿子”一步,显然链内原 yyy 的儿子并不被影响,而链外原 yyy 的儿子的权值必然比同深度链内原 yyy 的儿子的权值大,所以也不影响接下来取最小值的操作。
上述操作儿子的次数总和显然为 O(n)\Omicron (n)O(n) 级别,时间复杂度 O(nlog2n)\Omicron (n\log_2n)O(nlog2n),实现这个的方式异常多,我用的可并堆大力维护,但实际上只要用单次操作 O(log2n)\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. 闲话
又是被虐的一天啊。

553

被折叠的 条评论
为什么被折叠?



