bzoj 2212 : [Poi2011]Tree Rotations (线段树合并)
Posted kls123
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 2212 : [Poi2011]Tree Rotations (线段树合并)相关的知识,希望对你有一定的参考价值。
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2212
思路:用线段树合并求出交换左右儿子之前之后逆序对的数量,如果数量变小则交换.
实现代码:
#include<bits/stdc++.h> using namespace std; #define ll long long const int M = 4e5+10; int n,cnt,idx; ll ans,cnt1,cnt2; int v[M],l[M],r[M],root[M]; int sum[M*10],ls[M*10],rs[M*10]; void init_tree(int x){ scanf("%d",&v[x]); if(!v[x]){ l[x] = ++cnt; init_tree(l[x]); r[x] = ++cnt; init_tree(r[x]); } } void pushup(int rt){ sum[rt] = sum[ls[rt]] + sum[rs[rt]]; } void build(int p,int l,int r,int &rt){ if(!rt) rt = ++idx; if(l == r){ sum[rt] = 1; return ; } int mid = (l + r) >> 1; if(p <= mid) build(p,l,mid,ls[rt]); else build(p,mid+1,r,rs[rt]); pushup(rt); } int merge(int x,int y){ if(!x) return y; if(!y) return x; cnt1 += (ll)sum[rs[x]]*sum[ls[y]]; cnt2 += (ll)sum[ls[x]]*sum[rs[y]]; ls[x] = merge(ls[x],ls[y]); rs[x] = merge(rs[x],rs[y]); pushup(x); return x; } void solve(int x){ if(!x) return ; solve(l[x]); solve(r[x]); if(!v[x]){ cnt1 = cnt2 = 0; root[x] = merge(root[l[x]],root[r[x]]); ans += min(cnt1,cnt2); } } int main() { scanf("%d",&n); cnt = 1; init_tree(1); for(int i = 1;i <= cnt;i ++){ if(v[i]) build(v[i],1,n,root[i]); } solve(1); printf("%lld ",ans); return 0; }
以上是关于bzoj 2212 : [Poi2011]Tree Rotations (线段树合并)的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ_2212_[Poi2011]Tree Rotations_线段树合并
bzoj2212 [Poi2011]Tree Rotations 线段树合并
bzoj 2212[POI2011]ROT-Tree Rotations - 线段树合并
BZOJ 2212 [Poi2011]Tree Rotations