POI2011 Tree Rotations
阿新 • • 發佈:2018-08-05
urn lld sin name 統計 () esp git read
POI2011 Tree Rotations
給定一個n<=2e5個葉子的二叉樹,可以交換每個點的左右子樹。要求前序遍歷葉子的逆序對最少。
由於對於當前結點x,交換左右子樹,對於範圍之外的逆序對個數並沒有影響,所以可以進行線段樹合並,合並時統計l在左邊還是在右邊更優。
#include <cstdio> #include <cctype> using namespace std; typedef long long LL; inline void read(int &x){ char ch; x=0; for (; ch=getchar(), !isdigit(ch);); for (x=ch-48; ch=getchar(), isdigit(ch);) x=(x<<3)+(x<<1)+ch-48; } inline void read(LL &x){ char ch; x=0; for (; ch=getchar(), !isdigit(ch);); for (x=ch-48; ch=getchar(), isdigit(ch);) x=(x<<3)+(x<<1)+ch-48; } inline LL min(LL a,LL b) { return a > b?b : a; } const int maxn = 2e5+5; struct node { int seg,ls,rs; } a[maxn*30]; LL ANS = 0,ans1 = 0,ans2 = 0; int n; int cnt = 0; void modify(int &x,int l,int r, int pos) { if(!x) x = ++cnt; a[x].seg++; int mid=l+r>>1; if(l == r) return; if(pos <= mid) modify(a[x].ls,l,mid,pos); else modify(a[x].rs,mid+1,r,pos); } void merge(int &l,int r) { if(!l || !r) { l+=r; return; } a[l].seg += a[r].seg; ans1 += (LL)a[a[l].rs].seg*a[a[r].ls].seg; ans2 += (LL)a[a[l].ls].seg*a[a[r].rs].seg; merge(a[l].ls,a[r].ls); merge(a[l].rs,a[r].rs); } void solve(int &x) { int t,ls,rs; x = 0; read(t); if(!t) { solve(ls),solve(rs); ans1 = ans2 = 0; x = ls; merge(x,rs); ANS += min(ans1,ans2); } else modify(x,1,n,t); } int main() { read(n); int t = 0; solve(t); printf("%lld\n",ANS); return 0; }
POI2011 Tree Rotations