[bzoj3702] 二叉树

  一个节点的儿子是否交换,不会影响到它和兄弟节点间的逆序对数。

  所以每次合并线段树的时候算一下交换与不交换的逆序对数,然后选个较小值就行了。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 #define ll long long
 7 using namespace std;
 8 const int maxn=400233,mxnode=200233*20;
 9 int lc[mxnode],rc[mxnode],sz[mxnode],tot;
10 int ls[maxn],rs[maxn],size[maxn],mp[maxn],tt,rt[maxn];
11 int i,j,k,n,m,presz,P,id,root;
12 ll num0,num1,ans;
13  
14 int ra;char rx;
15 inline int read(){
16     rx=getchar(),ra=0;
17     while(rx<'0'||rx>'9')rx=getchar();
18     while(rx>='0'&&rx<='9')ra*=10,ra+=rx-48,rx=getchar();return ra;
19 }
20  
21 int merge(int a,int b){
22     if(!b){presz+=sz[a];return a;}
23     if(!a){num0+=1LL*sz[b]*presz;return b;}
24     sz[a]+=sz[b];
25     rc[a]=merge(rc[a],rc[b]),lc[a]=merge(lc[a],lc[b]);
26     return a;
27 }
28 void build(int &x,int a,int b){
29     x=++tot,sz[x]=1;
30     if(a==b)return;
31     int mid=a+b>>1;
32     if(P<=mid)build(lc[x],a,mid);else build(rc[x],mid+1,b);
33 }
34 void in(int &x){
35     x=++tt,id=read();
36     if(id)mp[x]=id,size[x]=1;else
37         in(ls[x]),in(rs[x]),size[x]=size[ls[x]]+size[rs[x]];
38 }
39 void dfs(int x){
40     if(size[x]==1){P=mp[x],build(rt[x],1,n);return;}
41     dfs(ls[x]),dfs(rs[x]),
42     presz=num0=0,rt[x]=merge(rt[ls[x]],rt[rs[x]]);
43     num1=1LL*size[ls[x]]*size[rs[x]]-num0;
44 //  printf("  %d %lld %lld\n",x,num0,num1);
45     ans+=min(num0,num1);
46 }
47 int main(){
48     n=read();
49     in(root);//printf("cnt: %d\n",cnt);
50     dfs(1);
51     printf("%lld\n",ans);
52     return 0;
53 }
View Code

 

posted @ 2016-06-18 17:09  czllgzmzl  阅读(211)  评论(0编辑  收藏  举报