BZOJ 2212 & POI 18 Tree Rotations(线段树合并)
来源:互联网 发布:python pyqt5实例 编辑:程序博客网 时间:2024/06/05 04:49
题意:给定一棵2n-1个节点的二叉树, 每个叶子上有1~n的数字, 保证每个数字出现且仅出现一次
允许任意次交换某两棵兄弟子树
对交换完毕的树求先序遍历, 形成1~n的一个排列
求这个排列最小的逆序对个数
1 ≤ n ≤ 2 * 1e5 (1e6)
思路:子树x内的逆序对个数为 :x 左子树内的逆序对个数 + x 右子树内的逆序对个数 + 跨越 x 左子树与右子树的逆
序对数。可以发现左右子树内部的逆序对与是否交换左右子树无关,是否交换左右子树取决于交换后 “跨越 x 左子树
与右子树的逆序对” 是否会减小。
可以用一些统计区间内数字个数 (cnt) 的线段树的合并来解决
在merge的过程中统计交换与不交换产生的逆序对数
a属于T的左子树, b属于T的右子树, ans0为不交换产生的逆序对数, ans1为交换产生的逆序对数
merge(a, b):
如果a, b中有一个为空, 就返回另一个
ans0 += cnt(a -> r) * cnt(b -> l)
ans1 += cnt(a -> l) * cnt(b -> r)
返回merge(a->l, b->l)与merge(a->r, b->r)连接形成的树的根
代码:
#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>using namespace std;typedef long long ll;const int maxn = 4e5+5;const int maxnode = 4e6+5;int n, sz, seg;ll ans, ans0, ans1;int tree[maxnode], lch[maxnode], rch[maxnode];int v[maxn], l[maxn], r[maxn], root[maxn];void init(){ sz = 1; ans = seg = 0; memset(v, 0, sizeof(v)); memset(root, 0, sizeof(root)); memset(tree, 0, sizeof(tree)); memset(lch, 0, sizeof(lch)); memset(rch, 0, sizeof(rch));}void readTree(int x){ scanf("%d", &v[x]); if(!v[x]) { l[x] = ++sz; readTree(l[x]); r[x] = ++sz; readTree(r[x]); }}void pushup(int rt){ tree[rt] = tree[lch[rt]]+tree[rch[rt]];}void build(int &rt, int l, int r, int val){ if(!rt) rt = ++seg; if(l == r) { tree[rt] = 1; return ; } int mid = (l+r)/2; if(val <= mid) build(lch[rt], l, mid, val); else build(rch[rt], mid+1, r, val); pushup(rt);}int merge(int x, int y){ if(!x) return y; if(!y) return x; ans0 += (ll)tree[rch[x]]*tree[lch[y]]; ans1 += (ll)tree[lch[x]]*tree[rch[y]]; lch[x] = merge(lch[x], lch[y]); rch[x] = merge(rch[x], rch[y]); pushup(x); return x;}void solve(int x){ if(!x) return ; solve(l[x]), solve(r[x]); if(!v[x]) { ans0 = ans1 = 0; root[x] = merge(root[l[x]], root[r[x]]); ans += min(ans0, ans1); }}int main(void){ while(cin >> n) { init(); readTree(1); for(int i = 1; i <= sz; i++) if(v[i]) build(root[i], 1, n, v[i]); solve(1); printf("%lld\n", ans); } return 0;}
阅读全文
1 0
- BZOJ 2212 & POI 18 Tree Rotations(线段树合并)
- 【bzoj 2212】Tree Rotations(线段树合并)
- bzoj 2212: [Poi2011]Tree Rotations 线段树合并
- bzoj 2212 [Poi2011]Tree Rotations(线段树合并)
- BZOJ 2212: [Poi2011]Tree Rotations 线段树合并
- BZOJ 2212 [Poi2011]Tree Rotations 线段树合并
- 【POI2011】Tree Rotations(线段树合并)
- bzoj 2212: [Poi2011]Tree Rotations (线段树)
- BZOJ 2212([Poi2011]Tree Rotations-启发式合并)
- [BZOJ2212][Poi2011]Tree Rotations(线段树合并)
- bzoj-2212 Tree Rotations
- Bzoj2212:[Poi2011]Tree Rotations:线段树的合并
- bzoj2212&3702 [Poi2011]Tree Rotations 二叉树 (线段树合并)
- BZOJ 2212: [Poi2011]Tree Rotations
- bzoj 2212: [Poi2011]Tree Rotations
- 【bzoj2212】[Poi2011]Tree Rotations(线段树的合并)(主席树-可持久化线段树)
- BZOJ 2212 [Poi 2011] 线段树合并 解题报告
- BZOJTree Rotations(线段树的合并)
- [leetcode] 78. Subsets
- HDOJ2037 今年暑假不AC (贪心,区间调度)
- 递归与动态规划---换钱的最少货币数(每种货币有无数张)
- JSP概述
- JavaSpiderParser
- BZOJ 2212 & POI 18 Tree Rotations(线段树合并)
- 支持向量机(SVM)入门(一~三)
- 【剑指offer】Java实现代码汇总
- 百练 2766 最大子矩阵 【思维 + dp思想】
- Linux入门——系统目录结构
- 递归与动态规划---换钱的最少货币数(每种货币只有一张)
- android mars老师学习笔记 知识点--目录!
- 使用Nodejs+Protractor搭建测试环境+Protractor的安装及其遇到的问题
- C#之操作注册表(RegistryKey类)