码迷,mamicode.com
首页 > 其他好文 > 详细

「Loj #2163」「Poi2011」Tree Rotations

时间:2020-04-18 09:28:42      阅读:47      评论:0      收藏:0      [点我收藏+]

标签:math   节点   esc   最小   main   权值线段树   注意   long   merge   

Description

现在有一棵二叉树,所有非叶子节点都有两个孩子。在每个叶子节点上有一个权值(有 \(n\) 个叶子节点,满足这些权值为 \(1\cdots n\) 的一个排列)。

可以任意交换每个非叶子节点的左右孩子。

要求进行一系列交换,使得最终所有叶子节点的权值按照遍历序写出来,逆序对个数最少。

Hint

\(1\le n\le 2\times 10^5\)

Solution

可以发现,对于其中一颗子树,不论如何变换都不会改变 这一颗子树中的结点与其他位置的结点组合产生的逆序对的个数 即这颗子树的变换不会改变上层之间的逆序对,所以只要考虑这颗子树中的就行了。

首先对所有结点开一个权值线段树,之后逐层合并即可。现在的问题就是,左右子树如何放置(是否交换)产生的逆序对最小。

我们可以在线段树合并的时候干这个事情。具体地,就是说当合并到结点 \(a\) (左子树结点) \(, b\)(右子树结点) 时,记 不交换产生的逆序对为 \(u\) ,交换的为 \(v\),那么:

  • \(u\) 加上 \(a\) 的右子树的大小 \(\times b\) 左子树的大小
  • \(v\) 加上 \(a\) 的左子树的大小 \(\times b\) 右子树的大小

一次合并完之后,\(\text{ans} \leftarrow \text{ans} + \min(u, v)\) 即可。

注意,实际节点数可能有 \(n\times 2\) 这么多,应开大空间。

Code

#include <iostream>
using namespace std;

const int N = 4e5 + 5;
const int S = N << 6;

int lc[S], rc[S], total = 0;
long long sum[S];
#define mid ((l + r) >> 1)
void increase(int &rt, int l, int r, int p) {
	if (!rt) rt = ++total;
	sum[rt]++;
	if (l == r) return;
	if (p <= mid) increase(lc[rt], l, mid, p);
	else increase(rc[rt], mid + 1, r, p);
}
int merge(int a, int b, int l, int r, long long& u, long long& v) {
	if (!a || !b) return a | b;
	if (l == r) return sum[a] += sum[b], a;
	u += sum[rc[a]] * sum[lc[b]];
	v += sum[lc[a]] * sum[rc[b]];
	lc[a] = merge(lc[a], lc[b], l, mid, u, v);
	rc[a] = merge(rc[a], rc[b], mid + 1, r, u, v);
	return sum[a] = sum[lc[a]] + sum[rc[a]], a;
}
#undef mid

int n;
long long ans = 0ll;
int solve() {
	int rt = 0, cur;
	cin >> cur;
	if (!cur) {
		int l = solve(), r = solve();
		long long u = 0ll, v = 0ll;
		rt = merge(l, r, 1, n, u, v);
		ans += min(u, v);
	} else increase(rt, 1, n, cur);
	return rt;
}

signed main() {
	cin >> n;
	solve();
	cout << ans << endl;
	return 0;
}

「Loj #2163」「Poi2011」Tree Rotations

标签:math   节点   esc   最小   main   权值线段树   注意   long   merge   

原文地址:https://www.cnblogs.com/-Wallace-/p/12723272.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!