[洛谷P3521][POI2011]ROT-Tree Rotations

题目大意:给一棵$n(n\leqslant2\times10^5)$个叶子的二叉树,可以交换每个点的左右子树,要求前序遍历叶子的逆序对最少。输出最少的逆序对个数

题解:线段树合并,对于每个节点求出交换左右子树和不交换的答案。

卡点:没开$long\;long$

 

C++ Code:

#include <cstdio>
#define maxn 200010
#define N maxn * 20
inline long long min(long long a, long long b) {return a < b ? a : b;}
int n, root;
long long ans, res0, res1;
int lc[N], rc[N], sum[N], idx;
int merge(int x, int y) {
	if (!x || !y) return x | y;
	res0 += static_cast<long long> (sum[lc[x]]) * sum[rc[y]];
	res1 += static_cast<long long> (sum[rc[x]]) * sum[lc[y]];
	sum[x] = sum[x] + sum[y];
	lc[x] = merge(lc[x], lc[y]);
	rc[x] = merge(rc[x], rc[y]);
	return x;
}
int insert(int l, int r, int val) {
	int rt = ++idx; sum[rt] = 1;
	if (l == r) return rt;
	int mid = l + r >> 1;
	if (val <= mid) lc[rt] = insert(l, mid, val);
	else rc[rt] = insert(mid + 1, r, val);
	return rt;
}
int init() {
	int x;
	scanf("%d", &x);
	if (x) return insert(1, n, x);
	else {
		int l = init(), r = init(), root;
		res0 = res1 = 0;
		root = merge(l, r);
		ans += min(res0, res1);
		return root;
	}
}

int main() {
	scanf("%d", &n);
	root = init();
	printf("%lld\n", ans);
	return 0;
}

  

posted @ 2018-11-02 18:05  Memory_of_winter  阅读(141)  评论(0编辑  收藏  举报