bzoj3702 二叉树
2017-01-26 21:15
176 查看
【题意】
一棵二叉树有n个叶子结点,每个叶子结点上有个权值,权值构成1~n的排列。每个非叶子结点均存在左右子树,可以交换每个非叶子结点的左右子树,使得权值按中序遍历写出后,逆序对个数最少。
【数据范围】
n<=200000
【思路】
每个结点独立处理
关键思路:启发式合并
整棵树从下到上,不断进行左右子树合并,如果枚举size较小的子树统计答案,则枚举复杂度为O(n log n)
[方法一]dfs序+主席树+每次枚举小区间
把每个子树看成区间,每次枚举小区间,查询大区间信息时使用主席树
[方法二]线段树合并
模板题,每次合并的同时统计答案,整个过程神似cdq分治
【时间复杂度】
[方法一]O(n log^2n)
[方法二]O(n log n)
【方法一】
一棵二叉树有n个叶子结点,每个叶子结点上有个权值,权值构成1~n的排列。每个非叶子结点均存在左右子树,可以交换每个非叶子结点的左右子树,使得权值按中序遍历写出后,逆序对个数最少。
【数据范围】
n<=200000
【思路】
每个结点独立处理
关键思路:启发式合并
整棵树从下到上,不断进行左右子树合并,如果枚举size较小的子树统计答案,则枚举复杂度为O(n log n)
[方法一]dfs序+主席树+每次枚举小区间
把每个子树看成区间,每次枚举小区间,查询大区间信息时使用主席树
[方法二]线段树合并
模板题,每次合并的同时统计答案,整个过程神似cdq分治
【时间复杂度】
[方法一]O(n log^2n)
[方法二]O(n log n)
【方法一】
#include<cstdio> #include<cstring> #include<algorithm> #define N 400010 #define ll long long using namespace std; struct pos{int l, r, mid;}pos ; struct tt{int l, r, sum;}t[N*15]; int n, w , ch [2], fa , nowfa, a , root , l, L, mid, R; ll ans, s1, s2; inline int read(){ int x=0, f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();} return x*f; } void dfs(int x){ if(!ch[x][0]){ a[++l]=w[x]; return; } pos[x].l=l+1; dfs(ch[x][0]); pos[x].mid=l; dfs(ch[x][1]); pos[x].r=l; } void ins(int i, int x, int L, int R){ t[l]=t[i]; t[l].sum++; if(L<R){ int mid=(L+R)>>1, l1=l; if(x<=mid){l++; t[l1].l=l; ins(t[i].l, x, L, mid);} else{l++; t[l1].r=l; ins(t[i].r, x, mid+1, R);} } } int c1(int x1, int x2, int x, int L, int R){ int sum=0, mid; while(L<R){ mid=(L+R)>>1; if(x<=mid){ x1=t[x1].l; x2=t[x2].l; R=mid; }else{ sum+=t[t[x1].l].sum-t[t[x2].l].sum; x1=t[x1].r; x2=t[x2].r; L=mid+1; } } sum+=t[x1].sum-t[x2].sum; return sum; } int c2(int x1, int x2, int x, int L, int R){ int sum=0, mid; while(L<R){ mid=(L+R)>>1; if(x<=mid){ sum+=t[t[x1].r].sum-t[t[x2].r].sum; x1=t[x1].l; x2=t[x2].l; R=mid; }else{ x1=t[x1].r; x2=t[x2].r; L=mid+1; } } sum+=t[x1].sum-t[x2].sum; return sum; } int main(){ n=read(); w[1]=read(); fa[1]=0; memset(ch, 0, sizeof(ch)); nowfa=1; for(int i=2; i<=n*2-1; i++){ w[i]=read(); fa[i]=nowfa; if(!ch[nowfa][0])ch[nowfa][0]=i; else ch[nowfa][1]=i; if(!w[i])nowfa=i; else while(ch[nowfa][1])nowfa=fa[nowfa]; } l=0; dfs(1); l=root[0]=0; for(int i=1; i<=n; i++){ l++; root[i]=l; ins(root[i-1], a[i], 1, n); } ans=0; for(int i=1; i<=n*2-1; i++)if(!w[i]){ L=pos[i].l; mid=pos[i].mid; R=pos[i].r; s1=s2=0; if(mid-L+1<=R-mid){ for(int j=L; j<=mid; j++){ s1+=c1(root[R], root[mid], a[j], 1, n); s2+=c2(root[R], root[mid], a[j], 1, n); } }else{ for(int j=mid+1; j<=R; j++){ s1+=c1(root[mid], root[L-1], a[j], 1, n); s2+=c2(root[mid], root[L-1], a[j], 1, n); } } ans+=min(s1, s2); } printf("%lld", ans); return 0; }【方法二】
//线段树合并 #include<cstdio> #include<cstring> #include<algorithm> #define N 400010 #define ll long long using namespace std; struct tt{int l, r, sum;}t[4000010]; int n, fa , ch [2], w , nowfa, p, root , l; ll ans, s1, s2; inline int read(){ int x=0, f=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();} return x*f; } void ins(int i, int x, int L, int R){ t[i].sum++; if(L<R){ int mid=(L+R)>>1; if(x<=mid){ if(!t[i].l)t[i].l=++l; ins(t[i].l, x, L, mid); }else{ if(!t[i].r)t[i].r=++l; ins(t[i].r, x, mid+1, R); } } } int merge(int x, int y){ if(!x)return y; if(!y)return x; s1+=(ll)t[t[x].l].sum*t[t[y].r].sum; s2+=(ll)t[t[x].r].sum*t[t[y].l].sum; t[x].l=merge(t[x].l, t[y].l); t[x].r=merge(t[x].r, t[y].r); t[x].sum+=t[y].sum; return x; } void dfs(int x){ if(!w[x]){ dfs(ch[x][0]); dfs(ch[x][1]); s1=s2=0; root[x]=merge(root[ch[x][0]], root[ch[x][1]]); ans+=min(s1, s2); } } int main(){ n=read()*2-1; memset(ch, 0, sizeof(ch)); w[1]=read(); fa[1]=0; nowfa=1; p=0; for(int i=2; i<=n; i++){ w[i]=read(); ch[nowfa][p]=i; fa[i]=nowfa; if(w[i]){ while(ch[nowfa][1])nowfa=fa[nowfa]; p=1; }else{nowfa=i; p=0;} } l=0; memset(root, 0, sizeof(root)); for(int i=1; i<=n; i++)if(w[i]){l++; root[i]=l; ins(l, w[i], 1, n/2+1);} ans=0; dfs(1); printf("%lld", ans); return 0; }
相关文章推荐
- 【bzoj3702】二叉树
- [bzoj3702]二叉树
- 【bzoj3702】【二叉树】【线段树】
- bzoj 3702: 二叉树
- bzoj3702 二叉树
- bzoj3702二叉树 线段树合并
- bzoj 3702: 二叉树 (线段树)
- [POI2011]Rotacje na drzewie (2)/[BZOJ3702]二叉树
- bzoj3702二叉树 线段树合并
- [bzoj3702]二叉树
- [bzoj3702] 二叉树
- 【bzoj3702】二叉树 权值线段树
- bzoj 3702: 二叉树 线段树合并
- bzoj 3702 二叉树
- BZOJ1864[ZJOI2006]三色二叉树[树形DP]
- bzoj 3625 小朋友和二叉树 多项式开根
- [bzoj3702/2212][Poi2011]二叉树/Tree Rotations_线段树
- 【BZOJ 1864】【ZJOI 2006】三色二叉树【树型DP】
- bzoj1864 [Zjoi2006]三色二叉树
- bzoj1864 [Zjoi2006]三色二叉树