首页 > 代码库 > 【bzoj2212&3702】二叉树

【bzoj2212&3702】二叉树

线段树合并入门题。

分别计算左子树的逆序对,右子树的逆序对,合并的时候计算贡献。

 1 #include<bits/stdc++.h>
 2 #define N 8000005
 3 using namespace std;
 4 typedef long long ll;
 5 int n,sz,tot,cnt=0;
 6 ll cnt1,cnt2,ans;
 7 int val[N],ls[N],rs[N],rt[N],sumv[N],l[N],r[N];
 8 inline int read(){
 9     int f=1,x=0;char ch;
10     do{ch=getchar();if(ch==-)f=-1;}while(ch<0||ch>9);
11     do{x=x*10+ch-0;ch=getchar();}while(ch>=0&&ch<=9);
12     return f*x;
13 }
14 void intree(int x){
15     val[x]=read();
16     if(!val[x]){
17         l[x]=++cnt;intree(l[x]);
18         r[x]=++cnt;intree(r[x]);
19     }
20 }
21 inline void pushup(int o){sumv[o]=sumv[ls[o]]+sumv[rs[o]];}
22 void build(int &o,int l,int r,int v){
23     if(!o)o=++cnt;if(l==r){sumv[o]=1;return;}
24     int mid=(l+r)>>1;
25     if(v<=mid)build(ls[o],l,mid,v);
26     else build(rs[o],mid+1,r,v);
27     pushup(o);
28 }
29 int merge(int x,int y){
30     if(!x)return y;if(!y)return x;
31     cnt1+=(ll)sumv[rs[x]]*sumv[ls[y]];
32     cnt2+=(ll)sumv[ls[x]]*sumv[rs[y]];
33     ls[x]=merge(ls[x],ls[y]);
34     rs[x]=merge(rs[x],rs[y]);
35     pushup(x);return x;
36 }
37 void solve(int x){
38     if(!x)return;
39     solve(l[x]);solve(r[x]);
40     if(!val[x]){
41         cnt1=cnt2=0;
42         rt[x]=merge(rt[l[x]],rt[r[x]]);
43         ans+=min(cnt1,cnt2);
44     }
45 }
46 int main(){
47     n=read();cnt++;
48     intree(1);
49     for(int i=1;i<=cnt;i++)if(val[i])build(rt[i],1,n,val[i]);
50     solve(1);
51     printf("%lld\n",ans);
52     return 0;
53 }

 

【bzoj2212&3702】二叉树