题目链接
bzoj 2212: [Poi2011]Tree Rotations
题解
一个子树之内交换儿子,对子树之外没有影响
所以对于每个节点的子数,交换与不交换,左右子树间形成的逆序对取min
每个节点维护权值线段树,线段树合并
代码
#include<bits/stdc++.h>
using namespace std;
inline int read() {
int x = 0,f = 1;char c = getchar();
while(c < '0' || c > '9'){if(c == '-') f= - 1; c = getchar();}
while(c <= '9' &&c >= '0')x = x * 10 + c- '0',c = getchar();
return x * f;
}
const int maxn = 2000007;
int n,tmp,sz[maxn * 10],lc[maxn * 10],tot = 0,rc[maxn * 10];
long long ans = 0,res1 = 0,res2 = 0;
int insert(int l,int r,int rk) {
sz[++ tot] = 1;
if(l == r) return tot;
int mid = l + r >> 1,rt = tot;
if(rk <= mid) lc[rt] = insert(l,mid,rk);
else rc[rt] = insert(mid + 1,r,rk);
return rt;
}
int merge(int l,int r,int x,int y) {
if(! x || ! y) return x ^ y;
if(l == r) { sz[ ++ tot] = sz[x] + sz[y]; return tot; }
int mid = l + r >> 1,rt = ++ tot;
res1 += 1ll * sz[rc[x]] * sz[lc[y]] , res2 += 1ll * sz[lc[x]] * sz[rc[y]];
lc[rt] = merge(l,mid,lc[x],lc[y]);
rc[rt] = merge(mid + 1,r,rc[x],rc[y]);
sz[rt] = sz[lc[rt]] + sz[rc[rt]];
return rt;
}
int dfs() {
tmp = read();
if(tmp) return insert(1,n,tmp);
int rt = merge(1,n,dfs(),dfs());
ans += min(res1,res2);
res1 = res2 = 0;
return rt;
}
int main() {
n = read();
dfs();
cout << ans << endl;
return 0;
}