P3521 [POI2011]ROT-Tree Rotations 题解

solution

因为是先序遍历,所以对于一颗子树,它在交换子树后改变的只有跨越左右子树的逆序对。所以只需要在向上合并的过程中统计答案就好了。

code

#include <bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define I inline
#define ll long long
#define CI const int
#define RI register int
#define W while
#define gc getchar
#define D isdigit(c=gc())
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define ms(a,x) memset((a),(x),sizeof(a))
using namespace std;
namespace SlowIO {
	I void readc (char& c) {W (isspace (c = gc ()));}
	Tp I void read (Ty& x) {char c; int f = 1; x = 0; W (! D) f = c ^ '-' ? 1 : -1; W (x = (x * 10) + (c ^ 48), D); x *= f;}
	Ts I void read (Ty& x, Ar&... y) {read (x); read (y...);}
} using namespace SlowIO;
CI N = 2e5, N4 = 5e6; int sum[N4 + 5], sl[N4 + 5], sr[N4 + 5], ntot = 0, n; ll ans, x, y;
void pushup (int root) {sum[root] = sum[sl[root]] + sum[sr[root]];}
void update (int &root, int L, int R, int pos) {
	if (! root) root = ++ ntot; if (L == R) {sum[root] += 1; return ;} int mid = (L + R) >> 1;
	if (pos <= mid) update (sl[root], L, mid, pos); else update (sr[root], mid + 1, R, pos); pushup (root);
}
int merge (int a, int b, int L, int R) {
	if (! a || ! b) return a + b; if (L == R) {sum[a] += sum[b]; return a;} int mid = (L + R) >> 1;
	x += (ll)sum[sr[a]] * sum[sl[b]]; y += (ll)sum[sr[b]] * sum[sl[a]]; sl[a] = merge (sl[a], sl[b], L, mid); sr[a] = merge (sr[a], sr[b], mid + 1, R); pushup (a); return a;
}
int dfs () {
	int root = 0, val; read (val); if (val == 0) {int ls, rs; ls = dfs (); rs = dfs (); x = y = 0; root = merge (ls, rs, 1, n); ans += min (x, y);}
	else update (root, 1, n, val); return root;
}
int main () {
	read (n); dfs (); printf ("%lld\n", ans);
	return 0;
}
posted @ 2022-08-21 22:53  ClapEcho233  阅读(14)  评论(0编辑  收藏  举报