士兵训练 题解
题意
link.
题解
正解会 RE 几个点,是官方的栈空间太小了。
再者网上几篇题解都被我 hack 了,好不容易找到一组 hack 却不是我错了,而是 STD 错了……
所以我来写篇题解造福社会。
观察到
那就维护一个子树内的最大、次大记为
但是我们需要在外面加一个
似乎再维护一个子树外最大
但是不对。
如果是只维护一个最大
此时问号情况就无法维护。
所以还要维护一个次大
(并且严格、不为零,否则就白维护了);
但此时还是不对,因为第三种情况还需要考虑到次次大,因此还需要维护一个严格的次次大
但,还没完。
如果有
完结撒花。
只不过维护
非常恶心,真的要看吗。
namespace zqh {
const int N = 200005;
int n, q, fa[N];
vector<int> g[N];
struct node {
int bmax; // 子树内攻击力最大
int b_max; // 次大
int b__max; // 再次大
int lmax, l_max, l__max, lmax_; // 子树内最大,子树外最大,子树外次大,子树内次大教导力
int fht, tch; // 攻击力,教导力
node() {
bmax = b__max = b_max = -1;
fht = tch = lmax = l_max = l__max = lmax_ = 0;
}
} b[N];
void dfs(int u) { // 计算树内
if (!u) return;
if (g[u].empty()) {
b[u].bmax = b[u].fht;
b[u].lmax = b[u].tch;
return;
}
vector<int> q, p;
q.push_back(b[u].fht);
for (int x : g[u]) {
dfs(x);
q.push_back(b[x].bmax);
q.push_back(b[x].b_max);
q.push_back(b[x].b__max);
p.push_back(b[x].lmax);
p.push_back(b[x].lmax_);
}
p.push_back(b[u].tch);
sort(p.begin(), p.end(), greater<int>());
sort(q.begin(), q.end(), greater<int>());
b[u].bmax = q[0];
b[u].b_max = q[1];
for (int i = 2; i < q.size(); i++)
if (q[i] != q[1]) {
b[u].b__max = q[i];
break;
}
b[u].lmax = p[0];
b[u].lmax_ = p[1];
for (int i = 1; i < p.size(); i++){
if (p[i] != b[u].lmax){
b[u].lmax_ = p[i];
break;
}
}
}
int get_l_max(int u) {
if (b[u].l_max) return b[u].l_max;
if (u == 1) {
return b[u].l_max = 0;
}
int t = fa[u];
int ans = b[t].tch;
for (int x : g[t]) {
if (x == u) continue;
ans = max(ans, b[x].lmax);
ans = max(ans, b[x].lmax_);
}
b[u].l_max = max(ans, get_l_max(t));
return b[u].l_max;
}
int get_l__max(int u) {
if (b[u].l__max) return b[u].l__max;
if (u == 1) {
return b[u].l__max = 0;
}
int t = fa[u];
vector<int> q;
q.push_back(b[t].tch);
for (int x : g[t]) {
if (x == u) continue;
q.push_back(b[x].lmax);
q.push_back(b[x].lmax_);
}
q.push_back(b[t].l_max);
q.push_back(get_l__max(t));
sort(q.begin(), q.end(), greater<int>());
for (int i = 0; i < q.size(); i++) {
if (q[i] != b[u].l_max) {
b[u].l__max = q[i];
break;
}
}
return b[u].l__max;
}
void calc_l_max() {
rep (i, 1, n) {
if (g[i].empty())
get_l_max(i);
}
}
void calc_l__max() { // 计算树外
rep (i, 1, n) {
if (g[i].empty())
get_l__max(i);
}
}
int dfs3(int u, int max_) {
int ans = 0;
if (b[u].fht != max_) {
ans = b[u].fht;
}
for (int x : g[u]) {
ans = max(ans, dfs3(x, max_));
}
return ans;
}
void init() {
cin >> n >> q;
rep (i, 2, n) {
cin >> fa[i];
g[fa[i]].push_back(i);
}
rep (i, 1, n) {
cin >> b[i].fht >> b[i].tch;
}
}
void solve() {
dfs(1);
calc_l_max();
calc_l__max();
rep (i, 1, n) { // 检查最、次大
if (b[i].l__max > b[i].l_max) swap(b[i].l__max, b[i].l_max);
if (b[i].lmax_ > b[i].lmax) swap(b[i].lmax_, b[i].lmax);
}
while (q--) { // 询问
int s;
cin >> s;
int l = b[s].l_max;
if (b[s].b_max == -1) { // 没有次大
cout << "0\n";
continue;
}
if (l + b[s].b_max > b[s].bmax) { // 第一种
cout << b[s].bmax << endl;
continue;
}
if (l + b[s].b_max < b[s].bmax) { // 第二种
cout << l + b[s].b_max << endl;
continue;
}
// 剩余就是第三种
if (b[s].b__max != b[s].b_max) { // 相等(也不可能不相等,可以不用判,毕竟是严格)
int ans = 0;
if (b[s].l_max + b[s].b__max < b[s].bmax && b[s].b__max != -1)
ans = max(ans, b[s].l_max + b[s].b__max);
if (b[s].l__max + b[s].b_max < b[s].bmax && b[s].b_max != -1)
ans = max(ans, b[s].l__max + b[s].b_max);
cout << ans << endl;
}
}
}
void main() {
init();
solve();
}
} // namespace zqh
赛时 80,后面死活 95 分,心态崩了。
后面才终于调对了。
最后,提供几组 hack,还要可以私信。
10 10
1 1 1 1 3 3 6 4 1 7 1
7 0
1 7
3 5
7 5
1 2
5 5
2 7
7 3
6 0
1
2
3
4
5
6
7
8
9
10
5
0
5
7
0
2
0
0
0
0
5
1 2 2 1
7 6
9 6
0 1
0 8
8 2
1
2
3
4
5
8
9
0
0
0
后记
列举一下被我叉掉的题解名单:
https://www.codeleading.com/article/48232048918/
https://blog.csdn.net/liyizhixl/article/details/78472619
https://blog.csdn.net/includelhc/article/details/81779245
未完待续
【推荐】博客园的心动:当一群程序员决定开源共建一个真诚相亲平台
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】Flutter适配HarmonyOS 5知识地图,实战解析+高频避坑指南
【推荐】开源 Linux 服务器运维管理面板 1Panel V2 版本正式发布
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 完成微博外链备案,微博中直接可以打开园子的链接
· 推荐 3 种 .NET Windows 桌面应用程序自动更新解决方案
· .NET 10 支持Linux/Unix 的Shebang(Hashbang)
· 上周热点回顾(6.9-6.15)
· 记一次 .NET 某SaaS版CRM系统 崩溃分析