题解 P3521 【[POI2011]ROT-Tree Rotations】
【Analysis 】
发现交换两个子树对其他的逆序不影响,只对跨两颗树的逆序对有影响,于是就有一个贪心;
1.权值线段树合并
从底至上,依次合并线段树,合并的时候可以顺便算一下交换和不交换产生的逆序对数,最后取
min ,时间复杂度O(nlog_2n) 常数较大的log_2 2.Dsu on Tree
对于跨子树的逆序对暴力算就好了,可以用树状数组;时间复杂度
O(nlog_2^2n) 常数较小的log_2^2
【Code1 】
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
inline int read()
{
int res = 0; bool f = 0; char c = getchar();
while ((c<'0')|(c>'9')) f ^= !(c^'-'), c = getchar();
while ((c>='0')&(c<='9')) res = (res<<1)+(res<<3)+(c^'0'),c = getchar();
return f ? -res : res;
}
typedef long long int64;
const int MaxN = 3e5 + 11;
struct Tree
{
int ls, rs, val;
} T[MaxN * 55];
int n, t, f;
int64 ans, ans1, ans2;
bool Is[MaxN];
inline void Mo(int& o, int v, int l = 1, int r = n)
{
T[(!o) ? (o = ++t) : o].val ++;
if (l == r) return ;
int mid = l + r >> 1;
v <= mid ? Mo(T[o].ls, v, l, mid) : Mo(T[o].rs, v, mid + 1, r);
}
inline void Merge(int &u, int v)
{
if (!u || !v) u = u | v;
else
{
T[u].val += T[v].val, ans1 += (int64)T[T[u].rs].val * T[T[v].ls].val,
ans2 += (int64)T[T[u].ls].val * T[T[v].rs].val,
Merge(T[u].ls, T[v].ls), Merge(T[u].rs, T[v].rs);
}
}
void Find(int& u)
{
int x = read(), ls, rs; u = 0;
if (!x)
{
Find(ls), Find(rs); ans1 = ans2 = 0;
Merge(ls, rs), u = ls, ans += ans1 < ans2 ? ans1 : ans2;
} else Mo(u, x);
}
int main(void) { n = read(), Find(f = 0), printf("%lld\n", ans); return 0; }
【Code2 】
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <vector>
inline char gc()
{
static char s[1<<20|1]={0},*p1=s,*p2=s;
return (p1==p2)&&(p2=(p1=s)+fread(s,1,1<<20,stdin),p1==p2)?EOF:*(p1++);
}
inline int read()
{
int res = 0; bool f = 0; char c = gc();
while ((c<'0')|(c>'9')) f ^= !(c^'-'), c = gc();
while ((c>='0')&(c<='9')) res = (res<<1)+(res<<3)+(c^'0'),c = gc();
return f ? -res : res;
}
typedef long long int64;
const int MaxN = 4e5 + 11;
int T[MaxN>>1], Size[MaxN], Hs[MaxN], L[MaxN], R[MaxN], Num[MaxN], Dfn[MaxN];
int n, t, son;
int64 ans, ans1, ans2;
inline void Mo(int p, int v) { for (;p <= n;) T[p] += v, p += p & -p; }
inline int Qu(int p) { int v = 0; for (;p;) v += T[p], p -= p & -p; return v; }
inline void Input(int id)
{
int x = read();
if (!x)
{
Dfn[id] = ++t, Input(L[id] = t + 1), Input(R[id] = t + 1),
Hs[id] = (Size[L[id]] >= Size[R[id]]) ? L[id] : R[id];
Size[id] = Size[L[id]] + Size[R[id]] + 1;
} else Num[id] = x, Size[id] = 1, Dfn[id] = ++t, Hs[id] = -1;
}
inline void Add(int u)
{
int v = Qu(n); ans1 = ans2 = 0;
for (int i = Dfn[u];i < Dfn[u] + Size[u]; ++i) if (Num[i])
{
int g = Qu(Num[i]);
ans1 += g, ans2 += v - g;
} for (int i = Dfn[u];i < Dfn[u] + Size[u]; ++i) if (Num[i]) Mo(Num[i], 1);
}
inline void Del(int u) { for (int i = Dfn[u];i < Dfn[u] + Size[u]; ++i) if (Num[i]) Mo(Num[i], -1); }
inline void Solve(int u, int is)
{
if (!~Hs[u]) { if (is) Mo(Num[u], 1); return ; }
if (Hs[u] != L[u])
{
Solve(L[u], 0), Solve(R[u], 1), son = R[u], Add(L[u]), ans += (ans1 < ans2) ? ans1 : ans2;
if (!is) Del(u);
}
else
{
Solve(R[u], 0), Solve(L[u], 1), son = L[u], Add(R[u]), ans += (ans1 < ans2) ? ans1 : ans2;
if (!is) Del(u);
}
}
int main(void)
{
n = read();
Input(1);
Solve(1, 1);
printf("%lld\n", ans);
return 0;
}