洛谷 P3521 [POI2011]ROT-Tree Rotations
Description
Solution
线段树合并
显然,两棵树的交换与他们的子树无关,所以从下往上处理即可。
我们考虑对于每个子节点建一只权值线段树。然后不断向上合并。
注意:每个点都是一只完整的权值线段树,也就是说左子树权值小于右子树权值。
所以逆序对个数就很明显了。
-
不交换: \(s1 += t[rs(u)].sum * t[ls(v)].sum\)
-
交换: \(s2 += t[ls(u)].sum * t[rs(v)].sum\)
Code
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#define ls(x) t[x].l
#define rs(x) t[x].r
#define ll long long
using namespace std;
const int N = 4e6 + 10;
int n, cnt;
ll s1, s2, ans;
struct Seg_tree{
int l, r, sum;
}t[N];
inline void update(int &x, int l, int r, int pos){
if(!x) x = ++cnt;
t[x].sum++;
if(l == r) return;
int mid = (l + r) >> 1;
if(pos <= mid) update(ls(x), l, mid, pos);
else update(rs(x), mid + 1, r, pos);
}
inline int merge(int u, int v, int l, int r){
if(!u || !v) return u | v;
t[u].sum += t[v].sum;
s1 += 1ll * t[rs(u)].sum * t[ls(v)].sum;
s2 += 1ll * t[ls(u)].sum * t[rs(v)].sum;
int mid = (l + r) >> 1;
ls(u) = merge(ls(u), ls(v), l, mid);
rs(u) = merge(rs(u), rs(v), mid + 1, r);
return u;
}
inline void dfs(int &x){
int t;
scanf("%d", &t);
if(!t){
int u = 0, v = 0;
dfs(u), dfs(v);
s1 = 0, s2 = 0;
x = u;
x = merge(x, v, 1, n);
ans += min(s1, s2);
}else update(x, 1, n, t);
}
int main(){
scanf("%d", &n);
int root = 0;
dfs(root);
printf("%lld\n", ans);
return 0;
}