士兵训练 题解

题意

link.

题解

正解会 RE 几个点,是官方的栈空间太小了。

再者网上几篇题解都被我 hack 了,好不容易找到一组 hack 却不是我错了,而是 STD 错了……

所以我来写篇题解造福社会。


观察到 max{bimodbj},则得到的结果一定比最大值小,则最大能取到次大。

那就维护一个子树内的最大、次大记为 bmaxb_max

但是我们需要在外面加一个 l

似乎再维护一个子树外最大 l 就行了。

但是不对。

如果是只维护一个最大 lmax

{lmax+b_max>bmax, bmaxlmax+b_max<bmax, lmax+b_maxlmax+b_max=bmax,?

此时问号情况就无法维护。

所以还要维护一个次大 l_max
(并且严格、不为零,否则就白维护了);

{lmax+b_max>bmax, bmaxlmax+b_max<bmax, lmax+b_maxlmax+b_max=bmax, b_max+l_max

但此时还是不对,因为第三种情况还需要考虑到次次大,因此还需要维护一个严格的次次大 b__max

{lmax+b_max>bmax, bmaxlmax+b_max<bmax, lmax+b_maxlmax+b_max=bmax, min(b_max+l_max,b__max+lmax)

但,还没完。

如果有 b_max=bmax 的情况……虽然有,但显然不够优,就不用考虑啦。

完结撒花。

只不过维护 lmaxl_max 的同时还要再维护一个 lmax_lmax__,表示子树内的最大值然后转移得到 lmax

非常恶心,真的要看吗。


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

未完待续

posted @   Archippus  阅读(15)  评论(0)    收藏  举报
相关博文:
阅读排行:
· 完成微博外链备案,微博中直接可以打开园子的链接
· 推荐 3 种 .NET Windows 桌面应用程序自动更新解决方案
· .NET 10 支持Linux/Unix 的Shebang(Hashbang)
· 上周热点回顾(6.9-6.15)
· 记一次 .NET 某SaaS版CRM系统 崩溃分析
点击右上角即可分享
微信分享提示