1. 程式人生 > >[洛谷P3521][POI2011]ROT-Tree Rotations

[洛谷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;
}