P4785 [BalticOI 2016 Day2] 交换 题解

看到 \(i\)\(\lfloor \frac{i}{2} \rfloor\),考虑一颗二叉树。题目的操作相当于按顺序交换当前节点和左右儿子的权值。

假设当前考虑的节点为 \(id\),左儿子为 \(ls\),右儿子为 \(rs\),当前这些点的值分别为 \(A,B,C\)

因为 \(id\) 的位置最靠前,最终又要字典序最小,所以要尽可能让 \(a_{id}\) 最小。

分三种情况讨论:

  • \(\min(A,B,C)=A\)

肯定都不交换,因为要贪心地使 \(a_{id}\) 最小,如果交换了任意一个的话 \(a_{id}\) 就肯定大于 \(A\) 了。

  • \(\min(A,B,C)=B\)

因为要让 \(a_{id}\) 最小,所以肯定会交换 \((id,ls)\),并且不会交换 \((id,rs)\)

  • \(\min(A,B,C)=C\)

会发现肯定要交换 \((id,rs)\),但是不确定要不要交换 \((id,ls)\),也就是不确定 \(A\) 放左边还是 \(B\) 放左边。直接贪心肯定不行,我们假设 \(mn = \min(A,B)\)。定义函数 \(f(id,val)\) 表示将当前节点为 \(id\),值为 \(val\),最终 \(val\) 的位置在哪。看 \(mn\) 放哪边的最终位置(即 \(f(ls,mn)\)\(f(rs,mn)\))更小即可。为啥?因为若 \(mn\) 不放最终位置更小的那边,那么这个位置的值肯定会更大,而放这个位置的话影响的位置更靠后,所以放小的这边更优。

那如何求 \(f(id,val)\) 呢,会发现对于同一个 \(id\),可能的 \(val\) 只有 \(\log\) 个(\(id\) 的祖先以及祖先的兄弟节点),那直接暴力转移再记忆化一下即可。

时间复杂度的瓶颈在求 \(f\),复杂度 \(O(n \log^2 n)\)

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN = 4e5 + 10;
int n,a[MAXN],ans[MAXN];
#define ls id << 1
#define rs id << 1 | 1
map <int,int> mp[MAXN];
inline int dfs(int id,int val) {
	if(mp[id].count(val)) return mp[id][val];
	int res = id,A = val,B = a[ls],C = a[rs];
	if(B == 0 && C == 0) res = id;
	else if(C == 0) {
		if(B < A) res = ls;
		else res = id;
	} else {
		if(A < B && A < C) res = id;
		else if(B < A && B < C) res = dfs(ls,val);
		else {
			int mx = max(A,B),mn = min(A,B);
			int LS = dfs(ls,mn),RS = dfs(rs,mn);
			if(A < B) res = min(LS,RS);
			else {
				if(LS < RS) res = dfs(rs,val);
				else res = dfs(ls,val);
			}
		}
	} return mp[id][val] = res;
}
inline void solve(int id) {
	int A = a[id],B = a[ls],C = a[rs];
	if(B == 0 && C == 0) return;
	else if(C == 0) {
		if(B < A) swap(a[id],a[ls]);
		return;   
	} else {
		if(A < B && A < C) solve(ls),solve(rs);
		else if(B < A && B < C) {
			swap(a[id],a[ls]);
			solve(ls),solve(rs); 
		} else {
			a[id] = C;
			int mx = max(A,B),mn = min(A,B);
			int LS = dfs(ls,mn),RS = dfs(rs,mn);
			if(LS < RS) a[ls] = mn,a[rs] = mx;
			else a[rs] = mn,a[ls] = mx;
			solve(ls),solve(rs);
		}
	} return;
}
signed main() {
	cin >> n;
	for(int i = 1;i <= n;i++) cin >> a[i];
	solve(1);
	for(int i = 1;i <= n;i++) cout << a[i] << " ";	
	return 0; 
} 

本文作者:Creeper_l

本文链接:https://www.cnblogs.com/Creeperl/p/18233783

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @ 2024-06-05 20:56  Creeper_l  阅读(9)  评论(0)    收藏  举报
  1. 1 イエスタデイ(翻自 Official髭男dism) 茶泡饭,春茶,kobasolo
  2. 2 世间美好与你环环相扣 柏松
  3. 3 True love tired
  4. 4 一笑江湖 (DJ弹鼓版) 闻人听書_
  5. 5 最好的安排 曲婉婷
  6. 6 星星在唱歌 司南
  7. 7 山川 李荣浩
  8. 8 On My Way Alan Walker
  9. 9 百战成诗 王者荣耀·100英雄官方群像献礼歌
  10. 10 雪 Distance Capper / 罗言
  11. 11 Edamame bbno$ / Rich Brian
  12. 12 半生雪 七叔-叶泽浩
  13. 13 Catch My Breath Kelly Clarkson
  14. 14 Love Is Gone SLANDER / Dylan Matthew
  15. 15 Endless Summer Alan Walker / Zak Abel
  16. 16 悬溺 葛东琪
  17. 17 风吹丹顶鹤 葛东琪
  18. 18 Normal No More TYSM
  19. 19 哪里都是你 队长
  20. 20 Stronger Kelly Clarkson
  21. 21 廖俊涛
  22. 22 消愁 毛不易
  23. 23 The Runner Yubik
  24. 24 踏山河 七叔-叶泽浩
  25. 25 Waiting For Love Avicii
  26. 26 在你的身边 盛哲
  27. 27 Dream It Possible Delacey
  28. 28 凄美地 郭顶
  29. 29 满天星辰不及你 ycc
  30. 30 侧脸 于果
  31. 31 阿拉斯加海湾 蓝心羽
  32. 32 虞兮叹 闻人听書_
  33. 33 离别开出花 就是南方凯
  34. 34 盗墓笔记·十年人间 李常超 (Lao乾妈)
凄美地 - 郭顶
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起