[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

 

转载于:https://www.cnblogs.com/czllgzmzl/p/5596499.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值