BZOJ2212 [Poi2011]Tree Rotations 線段樹合並 逆序對
阿新 • • 發佈:2017-12-21
htm namespace 逆序 post php .html mat () targe
原文鏈接http://www.cnblogs.com/zhouzhendong/p/8079786.html
題目傳送門 - BZOJ3286
題意概括
給一棵n(1≤n≤200000個葉子的二叉樹,可以交換每個點的左右子樹,要求前序遍歷葉子的逆序對最少。
題解
線段樹合並。
博主很懶,題解不寫了。
這份代碼是仿照別人的寫的。
代碼
#include <cstring> #include <cstdio> #include <cmath> #include <algorithm> #include <cstdlib> using namespace std; typedef long long LL; const int N=200005; int n,val[N*2],son[N*2][2],tot=0,rt; int root[N*2],ls[N*2*20],rs[N*2*20]; LL sum[N*2*20]; void dfsread(int &x){ x=++tot; scanf("%d",&val[x]); if (!val[x]){ dfsread(son[x][0]); dfsread(son[x][1]); } } void pushup(int rt){ sum[rt]=sum[ls[rt]]+sum[rs[rt]]; } LL sumL,sumR; void add(int &rt,int L,int R,int v){ rt=++tot; int mid=(L+R)>>1; if (L==R){ sum[rt]=1; return; } if (v<=mid) add(ls[rt],L,mid,v); else add(rs[rt],mid+1,R,v); pushup(rt); } int merge(int a,int b){ if (!a||!b) return a+b; sumL+=sum[rs[a]]*sum[ls[b]]; sumR+=sum[ls[a]]*sum[rs[b]]; ls[a]=merge(ls[a],ls[b]); rs[a]=merge(rs[a],rs[b]); pushup(a); return a; } LL dfs(int x){ LL ans=0; if (!val[x]){ ans=dfs(son[x][0])+dfs(son[x][1]); sumL=sumR=0; root[x]=merge(root[son[x][0]],root[son[x][1]]); ans+=min(sumL,sumR); } else add(root[x],1,n,val[x]); return ans; } int main(){ scanf("%d",&n); dfsread(rt); printf("%lld",dfs(rt)); return 0; }
BZOJ2212 [Poi2011]Tree Rotations 線段樹合並 逆序對