这道题采用权值线段树合并的解法。


首先讲一下解法中出现的两个概念:权值线段树与线段树合并。

所谓权值线段树,可以理解为维护的信息反过来的普通线段树,我个人认为值域线段树这个名字其实要准确一些。

举个例子,我们将序列$1,1,2,3,4,4,4,5,6,6$中的数依次插入,那么插入完成之后的效果图大概是下面这样的:

(其中红色为节点的值)

也就是说,每一个节点维护的值是这个区间内的数出现的次数。

在实现权值线段树时,我们通常会采用动态开点的方式,也就是不创建无关的节点,当然也可以离散化数据,否则必然会空间超限。

而线段树合并的原理则是基于线段树较为稳定的结构。

在合并的过程中,我们将两颗线段树对应位置的节点的值合在一起,创建一颗新的线段树。

过程大致如下:


这道题让我们求出逆序对个数最小值,并且允许我们随意交换一个节点的两棵子树。

考虑一个任意的节点,它的子树先序遍历后的逆序对显然只有三种组成:

1. 左子树中

2. 右子树中

3. 跨越左右子树

对子树的交换显然不会影响第1,2类,因此我们只需要计算出第三类的最小值即可。

至于计算则没有什么难度。由于我们维护的是值域,因此左儿子必定比右儿子大,那么我们就用左儿子大小乘以右儿子大小即可得出交换前逆序对个数。交换后同理之。

这里需要注意,我们能够这样计算是因为无论左右儿子怎么交换,影响的都只有当前部分的逆序对个数,而不会影响深度更浅的节点的值。

另:这道题处理输入十分窒息,可参考楼下写法。


AC代码如下:

509ms 57236kb

 #include<bits/stdc++.h>

 using namespace std;

 namespace StandardIO {

     template<typename T>inline void read (T &x) {
x=;T f=;char c=getchar();
for (; c<''||c>''; c=getchar()) if (c=='-') f=-;
for (; c>=''&&c<=''; c=getchar()) x=x*+c-'';
x*=f;
} template<typename T>inline void write (T x) {
if (x<) putchar('-'),x*=-;
if (x>=) write(x/);
putchar(x%+'');
} } using namespace StandardIO; namespace Solve { const int N=; int n;
long long ans,ans1,ans2;
int tot_node;
struct node {
int ls,rs;
long long val;
} tree[N*]; void update (int l,int r,int v,int &pos) {
if (!pos) pos=++tot_node;
tree[pos].val++;
if (l==r) return;
int mid=(l+r)>>;
if (v<=mid) update(l,mid,v,tree[pos].ls);
else update(mid+,r,v,tree[pos].rs);
}
void merge (int &x,int y) {
if (!x||!y) {
x=x+y;return;
}
tree[x].val+=tree[y].val;
ans1+=(long long)tree[tree[x].rs].val*tree[tree[y].ls].val;
ans2+=(long long)tree[tree[x].ls].val*tree[tree[y].rs].val;
merge(tree[x].ls,tree[y].ls);
merge(tree[x].rs,tree[y].rs);
}
void dfs (int &x) {
int tmp,ls,rs;x=;
read(tmp);
if (!tmp) {
dfs(ls),dfs(rs);
ans1=ans2=;
x=ls,merge(x,rs);
ans+=min(ans1,ans2);
} else update(,n,tmp,x);
} inline void solve () {
read(n);
int tmp=;
dfs(tmp);
write(ans);
}
} using namespace Solve; int main () {
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
solve();
}

题解 P3521 【[POI2011]ROT-Tree Rotations】的更多相关文章

  1. P3521 [POI2011]ROT-Tree Rotations (线段树合并)

    P3521 [POI2011]ROT-Tree Rotations 题意: 给你一颗树,只有叶子节点有权值,你可以交换一个点的左右子树,问你最小的逆序对数 题解: 线段树维护权值个个数即可 然后左右子 ...

  2. BZOJ2212: [Poi2011]Tree Rotations

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

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

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

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

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

  5. loj2163 / bzoj2212 / P3521 [POI2011]ROT-Tree Rotations(线段树合并)

    P3521 [POI2011]ROT-Tree Rotations loj2163 [POI2011]ROT-Tree Rotations(数据加强) (loj的数据套了个fread优化才过...) ...

  6. 2212: [Poi2011]Tree Rotations

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

  7. 洛谷 P3521 [POI2011]ROT-Tree Rotations 解题报告

    P3521 [POI2011]ROT-Tree Rotations 题意:递归给出给一棵\(n(1≤n≤200000)\)个叶子的二叉树,可以交换每个点的左右子树,要求前序遍历叶子的逆序对最少. 大体 ...

  8. POI2011 Tree Rotations

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

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

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

  10. bzoj 2212 Tree Rotations

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

随机推荐

  1. ORA-01658无法为表空间中的段创建INITIAL区

    导出空表设置时,提示错误是: ORA-01658无法为表空间中的段创建INITIAL区 查找解决方案为 表空间已满    设置表空间自动增长 即可 例:  alter database datafil ...

  2. js中es5 使用call方法继承实现 1.0

    function Parent(name){ this.name = name; this.showMess = function(){ return this.name; } } Parent.pr ...

  3. sass的用法小结(二)

    3. 导入SASS文件; css有一个特别不常用的特性,即@import规则,它允许在一个css文件中导入其他css文件.然而,后果是只有执行到@import时,浏览器才会去下载其他css文件,这导致 ...

  4. 路飞学城Python-Day3

    Moudle 1 Chapter 1 #练习题# 1.简述编译型与解释型语言的区别,且分别列出你知道的哪些语言属于编译型,哪些属于解释型?"""编译型:编译类指在应用源程 ...

  5. GET,POST请求

    get请求 post请求

  6. 将对象a的属性赋值给对象b

    BeanUtils.copyProperties(a,b); 将a的属性赋值给b(ab的共同属性)

  7. VB学习笔记(一)VB操作字符串

    在vb中 dim a# 定义a变量为双精度型变量~ #是类型符 % 整型 & 长整型 !单精度 $ 字符型 VB中strconv 的作用 StrConv("要转换的字符串" ...

  8. Java正则类

    ava.util.regex 类 Pattern java.lang.Object 继承者 java.util.regex.Pattern 所有已实现的接口: Serializable public ...

  9. 关于CAS操作

    在JDK 5之前Java语言是靠synchronized关键字保证同步的,这会导致有锁 锁机制存在以下问题: (1)在多线程竞争下,加锁.释放锁会导致比较多的上下文切换和调度延时,引起性能问题. (2 ...

  10. angular.js和vue.js中实现函数去抖(debounce)

    问题描述 搜索输入框中,只当用户停止输入后,才进行后续的操作,比如发起Http请求等. 学过电子电路的同学应该知道按键防抖.原理是一样的:就是说当调用动作n毫秒后,才会执行该动作,若在这n毫秒内又调用 ...