BZOJ 2212 线段树启发式合并
2017-09-19 17:14
399 查看
简略题意:现在有一棵二叉树,所有非叶子节点都有两个孩子。在每个叶子节点上有一个权值(有n个叶子节点,满足这些权值为1..n的一个排列)。可以任意交换每个非叶子节点的左右孩子。要求进行一系列交换,使得最终所有叶子节点的权值按照遍历序写出来,逆序对个数最少。
考虑题中的唯一操作,交换两个孩子。
对每个节点考虑两个孩子对答案的贡献:左孩子的贡献 + 右孩子的贡献 + 左孩子比右孩子大产生的贡献。
交换两个孩子只会使得第三种贡献变化,且只对当前节点有影响。
因此我们只需要考虑如何计算逆序对。
对节点建权值线段树,考虑将左右孩子的线段树合并时,不反转的情况下,每次统计左孩子对右孩子的影响的数量,然后递归合并下去。反转的情况下就是考虑右孩子对左孩子的影响。
其实这里本质上和cdq分治是一样的,可以做到统计贡献的不重不漏。
考虑题中的唯一操作,交换两个孩子。
对每个节点考虑两个孩子对答案的贡献:左孩子的贡献 + 右孩子的贡献 + 左孩子比右孩子大产生的贡献。
交换两个孩子只会使得第三种贡献变化,且只对当前节点有影响。
因此我们只需要考虑如何计算逆序对。
对节点建权值线段树,考虑将左右孩子的线段树合并时,不反转的情况下,每次统计左孩子对右孩子的影响的数量,然后递归合并下去。反转的情况下就是考虑右孩子对左孩子的影响。
其实这里本质上和cdq分治是一样的,可以做到统计贡献的不重不漏。
#include <bits/stdc++.h> #define all(x) x.begin(), x.end() using namespace std; const int maxn = 4400000; int n; int cid; int root[maxn], l[maxn], r[maxn], v[maxn]; struct Seg { int l, r, sum; } tr[maxn]; void pushup(int x) { tr[x].sum = tr[tr[x].l].sum + tr[tr[x].r].sum; } int update(int pos, int l, int r) { int x = ++cid; int m = l + r >> 1; if(l == r) { tr[x].sum = 1; return x; } if(pos <= m) tr[x].l = update(pos, l, m); else tr[x].r = update(pos, m+1, r); pushup(x); return x; } int sz = 1; void read(int x) { scanf("%d", &v[x]); if(v[x] == 0) { l[x] = ++sz; read(l[x]); r[x] = ++sz; read(r[x]); } else { root[x] = update(v[x], 1, n); } } long long ans = 0, s1 = 0, s2 = 0; int mergetree(int x, int y, int tp) { if(!x) return y; if(!y) return x; if(tp == 1) { s1 += 1LL * tr[tr[x].r].sum * tr[tr[y].l].sum; s2 += 1LL * tr[tr[x].l].sum * tr[tr[y].r].sum; } else { s2 += 1LL * tr[tr[x].r].sum * tr[tr[y].l].sum; s1 += 1LL * tr[tr[x].l].sum * tr[tr[y].r].sum; } tr[x].l = mergetree(tr[x].l, tr[y].l, tp); tr[x].r = mergetree(tr[x].r, tr[y].r, tp); pushup(x); return x; } void dfs(int x) { if(!x) return ; dfs(l[x]), dfs(r[x]); if(!v[x]) { s1 = s2 = 0; if(tr[root[l[x]]].sum > tr[root[r[x]]].sum) root[x] = mergetree(root[l[x]], root[r[x]], 1); else root[x] = mergetree(root[r[x]], root[l[x]], 2); ans += min(s1, s2); } } void init() { cid = 0; } int main() { init(); scanf("%d", &n); read(1); dfs(1); printf("%lld\n", ans); return 0; }
相关文章推荐
- bzoj 2212(线段树合并)
- [BZOJ3702][BZOJ2212]-线段树合并
- 【bzoj 2212】Tree Rotations(线段树合并)
- 【BZOJ2212】Tree Rotations(POI2011)-平衡树启发式合并
- bzoj 2212 [Poi2011]Tree Rotations(线段树合并)
- BZOJ 2212 [Poi 2011] 线段树合并 解题报告
- BZOJ 2212 [Poi2011]Tree Rotations 线段树合并
- bzoj 2733: [HNOI2012]永无乡(线段树启发式合并)
- bzoj 2733: [HNOI2012]永无乡(线段树启发式合并)
- BZOJ 2212: [Poi2011]Tree Rotations 线段树合并
- BZOJ 2212([Poi2011]Tree Rotations-启发式合并)
- BZOJ.4919.[Lydsy1706月赛]大根堆(线段树合并/启发式合并)
- bzoj 3123: [Sdoi2013]森林 启发式合并+可持久化线段树
- bzoj 2212: [Poi2011]Tree Rotations 线段树合并
- [线段树 启发式合并] BZOJ 2733 永无乡
- [ 树上启发式合并 线段树 单调栈 ] BZOJ5040
- [BZOJ2212][POI2011]Tree Rotations(线段树合并)
- BZOJ_2212_[Poi2011]Tree Rotations_线段树合并
- BZOJ2212 POI2011Tree Rotations(线段树合并)
- [bzoj 2733]启发式合并权值线段树