3702: 二叉树
Time Limit: 15 Sec Memory Limit: 256 MBSubmit: 665 Solved: 307
[Submit][Status][Discuss]
Description
现在有一棵二叉树,所有非叶子节点都有两个孩子。在每个叶子节点上有一个权值(有n个叶子节点,满足这些权值为1..n的一个排列)。可以任意交换每个非叶子节点的左右孩子。
要求进行一系列交换,使得最终所有叶子节点的权值按照中序遍历写出来,逆序对个数最少。
Input
第一行n
下面每行,一个数x
如果x==0,表示这个节点非叶子节点,递归地向下读入其左孩子和右孩子的信息,
如果x!=0,表示这个节点是叶子节点,权值为x。
Output
一行,最少逆序对个数。
Sample Input
3
0
0
3
1
2
0
0
3
1
2
Sample Output
1
HINT
对于100%的数据:2<=n<=200000。
Source
直接上线段树合并即可
https://www.cnblogs.com/Mychael/p/8665589.html
/************************************************************** Problem: 3702 User: zhangenming Language: C++ Result: Accepted Time:7324 ms Memory:86028 kb ****************************************************************/ #include <bits/stdc++.h> #define ll long long #define inf 1e9+10 #define ull unsigned long long #define eps 1e-7 using namespace std; inline int read(){ int x=0;int f=1;char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();} while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();} return x*f; } const int MAXN=1e6+10; struct sig{ int sum,ls,rs; }T[MAXN<<2]; int rt[MAXN],n,l[MAXN],r[MAXN],vl[MAXN],tot,siz; ll sum1,sum2,ans; inline void build(int &x){ int t=read();x=++tot; if(t==0) build(l[x]),build(r[x]); else vl[x]=t; } inline void ins(int l,int r,int &rt,int t){ if(!rt) rt=++siz; T[rt].sum++; if(l==r) return; int mid=(l+r)>>1; if(t<=mid) ins(l,mid,T[rt].ls,t); else ins(mid+1,r,T[rt].rs,t); } inline int merge(int x,int y){ if(!x||!y) return x+y; sum1+=1LL*T[T[x].rs].sum*T[T[y].ls].sum; sum2+=1LL*T[T[x].ls].sum*T[T[y].rs].sum; T[x].sum+=T[y].sum; T[x].ls=merge(T[x].ls,T[y].ls); T[x].rs=merge(T[x].rs,T[y].rs); return x; } inline void dfs(int x){ if(vl[x]){ ins(1,n,rt[x],vl[x]); } else{ dfs(l[x]);dfs(r[x]); sum1=sum2=0; rt[x]=merge(rt[l[x]],rt[r[x]]); ans+=min(sum1,sum2); } } int main(){ n=read(); int root; build(root); dfs(root); printf("%lld ",ans); return 0; }