bzoj3702/bzoj2212 二叉树 (线段树合并)

用线段树记每个子树中包含的数,然后合并的时候算出来逆序对的数量(合并a,b时,就是size[ch[a][1]]*size[ch[b][0]]),来决定这个子树要不要翻转

 1 #include<bits/stdc++.h>
 2 #define pa pair<int,int>
 3 #define CLR(a,x) memset(a,x,sizeof(a))
 4 using namespace std;
 5 typedef long long ll;
 6 const int maxn=2e5+10,logn=1e7;
 7 
 8 inline ll rd(){
 9     ll x=0;char c=getchar();int neg=1;
10     while(c<'0'||c>'9'){if(c=='-') neg=-1;c=getchar();}
11     while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
12     return x*neg;
13 }
14 
15 int siz[logn],ch[logn][2],pct;
16 int N;
17 ll ans;
18 
19 void insert(int &p,int l,int r,int x){
20     if(!p) p=++pct;
21     siz[p]++;
22     if(l==r) return;
23     int m=l+r>>1;
24     if(x<=m) insert(ch[p][0],l,m,x);
25     else insert(ch[p][1],m+1,r,x);
26 }
27 
28 ll merge(int &a,int b,int l,int r){
29     if(!b) return 0;
30     if(!a){a=b;return 0;}
31     siz[a]+=siz[b];
32     if(l==r) return 0;
33     ll re=1ll*siz[ch[a][1]]*siz[ch[b][0]];
34     int m=l+r>>1;
35     re+=merge(ch[a][0],ch[b][0],l,m);
36     re+=merge(ch[a][1],ch[b][1],m+1,r);
37     return re;
38 }
39 
40 int dfs(){
41     int x=rd();
42     if(x!=0){
43         int rt=0;
44         insert(rt,1,N,x);
45         return rt;
46     }
47     int lc=dfs(),rc=dfs();
48     ll sm=1ll*siz[lc]*siz[rc];
49     if(siz[lc]>siz[rc]) swap(lc,rc);
50     ll re=merge(lc,rc,1,N);
51     ans+=min(re,sm-re);
52     return lc;
53 }
54 
55 int main(){
56     //freopen(".in","r",stdin);
57     int i,j,k;
58     N=rd();
59     dfs();
60     printf("%lld\n",ans);
61     return 0;
62 }

 

posted @ 2018-10-28 21:15  Ressed  阅读(237)  评论(0编辑  收藏  举报