BZOJ 2212

从下到上线段树合并。

考虑到每一个子树内部产生的贡献不可能通过换儿子消除,所以一次更换只要看看把哪个儿子放在左边产生的逆序对数少就可以了。

逆序对数可以在线段树合并的时候顺便算出来。

由于只有叶子结点有权值 + 二叉树的特性,大大方便了这道题的代码和细节处理。

注意点数总共要开到$2 * n$。

时间复杂度$O(nlogn)$。

Code:

#include <cstdio>
#include <cstring>
using namespace std;
typedef long long ll; const int N = 4e5 + ; int m, n = , rt = ;
ll ans = 0LL; struct Node {
int lc, rc, w;
} a[N]; inline void read(int &X) {
X = ; char ch = ; int op = ;
for(; ch > '' || ch < ''; ch = getchar())
if(ch == '-') op = -;
for(; ch >= '' && ch <= ''; ch = getchar())
X = (X << ) + (X << ) + ch - ;
X *= op;
} inline ll min(ll x, ll y) {
return x > y ? y : x;
} void build(int &now) {
now = ++n;
read(a[now].w);
if(a[now].w) return;
build(a[now].lc), build(a[now].rc);
} namespace SegT {
struct Node {
int lc, rc;
ll siz;
} s[N * ]; int sta[N * ], top = , root[N], nodeCnt = ;
ll res1, res2; inline void push(int now) {
sta[++top] = now;
} inline int newNode() {
if(top) return sta[top--];
else return ++nodeCnt;
} #define lc(p) s[p].lc
#define rc(p) s[p].rc
#define siz(p) s[p].siz
#define mid ((l + r) >> 1) inline void up(int p) {
if(!p) return;
siz(p) = siz(lc(p)) + siz(rc(p));
} void ins(int &p, int l, int r, int x) {
if(!p) p = newNode();
++siz(p);
if(l == r) return; if(x <= mid) ins(lc(p), l, mid, x);
else ins(rc(p), mid + , r, x);
} int merge(int u, int v, int l, int r) {
if(!u || !v) return u + v; res1 += siz(rc(u)) * siz(lc(v));
res2 += siz(rc(v)) * siz(lc(u)); int p = newNode();
if(l == r) siz(p) = siz(u) + siz(v);
else {
lc(p) = merge(lc(u), lc(v), l, mid);
rc(p) = merge(rc(u), rc(v), mid + , r);
up(p);
}
push(u), push(v);
return p;
} void print(int p, int l, int r) {
if(l == r) {
printf("%lld", siz(p));
return;
} print(lc(p), l, mid), print(rc(p), mid + , r);
} inline void deb(int x) {
print(root[x], , m);
} #undef lc
#undef rc
#undef mid
#undef siz } using namespace SegT; void solve(int now) {
if(a[now].w) return;
solve(a[now].lc), solve(a[now].rc); res1 = res2 = 0LL;
root[now] = merge(root[a[now].lc], root[a[now].rc], , m);
ans += min(res1, res2);
} int main() {
read(m);
build(rt); /* for(int i = 1; i <= n; i++)
printf("%d %d %d\n", a[i].lc, a[i].rc, a[i].w);
printf("\n"); */ for(int i = ; i <= n; i++)
if(a[i].w) ins(root[i], , m, a[i].w); /* for(int i = 1; i <= n; i++) {
if(!a[i].w) continue;
deb(i);
printf("\n");
} */ solve(rt); printf("%lld\n", ans);
return ;
}

Luogu 3521 [POI2011]ROT-Tree Rotations的更多相关文章

  1. BZOJ2212: [Poi2011]Tree Rotations

    2212: [Poi2011]Tree Rotations Time Limit: 20 Sec  Memory Limit: 259 MBSubmit: 391  Solved: 127[Submi ...

  2. BZOJ 2212: [Poi2011]Tree Rotations( 线段树 )

    线段树的合并..对于一个点x, 我们只需考虑是否需要交换左右儿子, 递归处理左右儿子. #include<bits/stdc++.h> using namespace std; #defi ...

  3. 2212: [Poi2011]Tree Rotations

    2212: [Poi2011]Tree Rotations https://www.lydsy.com/JudgeOnline/problem.php?id=2212 分析: 线段树合并. 首先对每个 ...

  4. 【BZOJ2212】[Poi2011]Tree Rotations 线段树合并

    [BZOJ2212][Poi2011]Tree Rotations Description Byteasar the gardener is growing a rare tree called Ro ...

  5. POI2011 Tree Rotations

    POI2011 Tree Rotations 给定一个n<=2e5个叶子的二叉树,可以交换每个点的左右子树.要求前序遍历叶子的逆序对最少. 由于对于当前结点x,交换左右子树,对于范围之外的逆序对 ...

  6. [bzoj3702/2212][Poi2011]二叉树/Tree Rotations_线段树

    二叉树 Tree Rotations bzoj-3702 bzoj-2212 Poi-2011 题目大意:现在有一棵二叉树,所有非叶子节点都有两个孩子.在每个叶子节点上有一个权值(有n个叶子节点,满足 ...

  7. bzoj 2212 Tree Rotations

    bzoj 2212 Tree Rotations 考虑一个子树 \(x\) 的左右儿子分别为 \(ls,rs\) .那么子树 \(x\) 内的逆序对数就是 \(ls\) 内的逆序对数,\(rs\) 内 ...

  8. Luogu 3690 Link Cut Tree

    Luogu 3690 Link Cut Tree \(LCT\) 模板题.可以参考讲解和这份码风(个人认为)良好的代码. 注意用 \(set\) 来维护实际图中两点是否有直接连边,否则无脑 \(Lin ...

  9. 线段树合并(【POI2011】ROT-Tree Rotations)

    线段树合并([POI2011]ROT-Tree Rotations) 题意 现在有一棵二叉树,所有非叶子节点都有两个孩子.在每个叶子节点上有一个权值(有nn个叶子节点,满足这些权值为1-n1-n的一个 ...

随机推荐

  1. datatable绑定comboBox,在下拉菜单中显示对应数据

    实现功能: datatable绑定comboBox,在下拉菜单中显示对应数据 实现方法: .生成datatable,并为combox绑定数据源: comboBox1.DataSource = dt1; ...

  2. SQL使用指南(1)—— 数据定义语言(DDL)

    1.使用create 语句创建表 CREATE TABLE table_name (column_name datatype[null|not null], column_name datatype[ ...

  3. 超简单tensorflow入门优化程序&&tensorboard可视化

    程序1 任务描述: x = 3.0, y = 100.0, 运算公式 x×W+b = y,求 W和b的最优解. 使用tensorflow编程实现: #-*- coding: utf-8 -*-) im ...

  4. Android源代码因删除所有git仓库导致的编译错误

    /******************************************************************************** * Android源代码因删除所有g ...

  5. C#进阶之路(四):拉姆达

    对于拉姆达,许多文章都讲过原理及如何使用,所以这篇文章我主要是摘录我学习过的文字,总结下我自己的学习心得. 什么是拉姆达表达式 "Lambda表达式"是一个匿名函数,是一种高效的类 ...

  6. GO语言heap剖析及利用heap实现优先级队列

    GO语言heap剖析 本节内容 heap使用 heap提供的方法 heap源码剖析 利用heap实现优先级队列 1. heap使用 在go语言的标准库container中,实现了三中数据类型:heap ...

  7. hw_module_t 加载过程

    每一个HAL模块都有一个ID值,以这些ID值为参数来调用硬件抽象层提供的函数hw_get_module就可以将指定的模块加载到内存来,并且获得 一个hw_module_t接口来打开相应的设备. 函数h ...

  8. Linux 优秀软件

    本文由Suzzz原创,发布于 http://www.cnblogs.com/Suzzz/p/4038925.html ,转载请保留此声明 一些Linux下的优秀软件,个人非常喜欢.都在Ubuntu14 ...

  9. FPGA中竞争冒险问题的研究

    什么是竞争冒险? 1 引言     现场可编程门阵列(FPGA)在结构上由逻辑功能块排列为阵列,并由可编程的内部连线连接这些功能块,来实现一定的逻辑功能. FPGA可以替代其他PLD或者各种中小规模数 ...

  10. 拨打电话demo

    - (IBAction)btnClick:(id)sender { UIActionSheet *action = [[UIActionSheet alloc] initWithTitle:nil d ...