【Luogu】P3521ROT-Tree Rotations(线段树合并)
神奇的线段树合并qwq 不过就思路而言很好想……
观察到一棵树无论怎么交换两棵左右子树,子树内部的最优逆序对并没影响……决策只影响左右子树之间的逆序对……
于是线段树合并直接乱搞就好啦
#include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<cctype> #define mid ((l+r)>>1) #define check(x) if(x==0) x=++tot; #define maxn 400200 using namespace std; inline long long read(){ long long num=0,f=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='-') f=-1; ch=getchar(); } while(isdigit(ch)){ num=num*10+ch-'0'; ch=getchar(); } return num*f; } long long ls[maxn]; long long rs[maxn]; long long q[maxn]; long long root[maxn]; long long lc[maxn*10]; long long rc[maxn*10]; long long tree[maxn*10]; long long f[maxn]; long long c,w; long long ans; long long n,tot,cnt; inline void pushup(long long rt){ tree[rt]=tree[lc[rt]]+tree[rc[rt]]; } void update(long long o,long long l,long long r,long long &rt){ check(rt); if(l==r){ tree[rt]++; return; } if(o<=mid) update(o,l,mid,lc[rt]); else update(o,mid+1,r,rc[rt]); pushup(rt); } void gettree(long long &x){ x=++cnt; q[x]=read(); if(q[x]) return; gettree(ls[x]); gettree(rs[x]); return; } long long merge(long long x,long long y){ if(x==0) return y; if(y==0) return x; c+=tree[rc[x]]*tree[lc[y]]; w+=tree[lc[x]]*tree[rc[y]]; lc[x]=merge(lc[x],lc[y]); rc[x]=merge(rc[x],rc[y]); pushup(x); return x; } void calc(long long x){ if(q[x]) return; calc(ls[x]); calc(rs[x]); c=w=0; root[x]=merge(root[ls[x]],root[rs[x]]); ans+=min(c,w); return; } void build(long long x){ if(q[x]){ update(q[x],1,n,root[x]); return; } build(ls[x]); build(rs[x]); return; } long long Root; int main(){ n=read(); gettree(Root); build(1); calc(1); printf("%lld",ans); return 0; }