1. 程式人生 > >BZOJ2212 Poi2011Tree Rotations(線段樹合並)

BZOJ2212 Poi2011Tree Rotations(線段樹合並)

|| 線段樹 merge stdin using add clu ota pac

顯然子樹內的操作不會對子樹外產生影響。於是貪心,若交換之後子樹內逆序對減少就交換。

這個東西可以用權值線段樹計算。操作完畢後需要對兩棵權值線段樹合並,這個的復雜度是兩棵線段樹的重復節點個數。那麽總復雜度不太顯然的是O(nlogn)。因為相當於把n個只有一個葉子的線段樹合並在一起。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace
std; int read() { int x=0,f=1;char c=getchar(); while (c<0||c>9) {if (c==-) f=-1;c=getchar();} while (c>=0&&c<=9) x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N 400010 int n,cnt=0,tot=0,root[N]; long long ans=0,ansl,ansr; struct data{int l,r,x;}tree[N<<5
]; void add(int &k,int l,int r,int x) { if (!k) k=++cnt; tree[k].x++; if (l==r) return; int mid=l+r>>1; if (x<=mid) add(tree[k].l,l,mid,x); else add(tree[k].r,mid+1,r,x); } int merge(int x,int y,int l,int r) { if (!x||!y) return x|y; ansl+=1ll*tree[tree[x].l].x*tree[tree[y].r].x; ansr
+=1ll*tree[tree[x].r].x*tree[tree[y].l].x; tree[x].x+=tree[y].x; int mid=l+r>>1; tree[x].l=merge(tree[x].l,tree[y].l,l,mid), tree[x].r=merge(tree[x].r,tree[y].r,mid+1,r); return x; } int get() { int x=read(),t=++tot; if (x) add(root[t],1,n,x); else { int l=get(),r=get(); ansl=0,ansr=0; root[t]=merge(root[l],root[r],1,n); ans+=min(ansl,ansr); } return t; } int main() { freopen("bzoj2212.in","r",stdin); freopen("bzoj2212.out","w",stdout); n=read(); get(); cout<<ans; fclose(stdin);fclose(stdout); return 0; }

BZOJ2212 Poi2011Tree Rotations(線段樹合並)