线段树合并,又学了一个破玩意儿,推荐黄嘉泰大神的PPT
实际操作跟主席树差不了多少吧(或者说弱化版主席树??)
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; int n,z,a[8100000],lc[8100000],rc[8100000]; int initytree() { int now=++z; scanf("%d",&a[now]); if(a[now]==0) { lc[now]=initytree(); rc[now]=initytree(); } return now; } struct trnode { int lc,rc,c; }tr[8100000];int trlen,rt[8100000]; int maketree(int x,int l,int r,int p) { if(x==0)x=++trlen; if(l==r){tr[x].c=1;return x;} int mid=(l+r)/2; if(p<=mid)tr[x].lc=maketree(tr[x].lc,l,mid,p); else tr[x].rc=maketree(tr[x].rc,mid+1,r,p); tr[x].c=tr[tr[x].lc].c+tr[tr[x].rc].c; return x; } LL ans,ans1,ans2; int merge(int x,int y) { if(x==0||y==0)return x+y; ans1+=(LL(tr[tr[x].lc].c))*(LL(tr[tr[y].rc].c)); ans2+=(LL(tr[tr[x].rc].c))*(LL(tr[tr[y].lc].c)); tr[x].c+=tr[y].c; tr[x].lc=merge(tr[x].lc,tr[y].lc); tr[x].rc=merge(tr[x].rc,tr[y].rc); return x; } void solve(int x) { if(a[x]!=0)return ; solve(lc[x]);solve(rc[x]); ans1=0;ans2=0; rt[x]=merge(rt[lc[x]],rt[rc[x]]); ans+=min(ans1,ans2); } int main() { scanf("%d",&n); z=0;int root=initytree(); for(int i=1;i<=z;i++) if(a[i]!=0)rt[i]=maketree(rt[i],1,n,a[i]); ans=0; solve(root); printf("%lld ",ans); return 0; }