题解 P3521 【[POI2011]ROT-Tree Rotations】
这道题采用权值线段树合并的解法。
首先讲一下解法中出现的两个概念:权值线段树与线段树合并。
所谓权值线段树,可以理解为维护的信息反过来的普通线段树,我个人认为值域线段树这个名字其实要准确一些。
举个例子,我们将序列$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】的更多相关文章
- P3521 [POI2011]ROT-Tree Rotations (线段树合并)
P3521 [POI2011]ROT-Tree Rotations 题意: 给你一颗树,只有叶子节点有权值,你可以交换一个点的左右子树,问你最小的逆序对数 题解: 线段树维护权值个个数即可 然后左右子 ...
- BZOJ2212: [Poi2011]Tree Rotations
2212: [Poi2011]Tree Rotations Time Limit: 20 Sec Memory Limit: 259 MBSubmit: 391 Solved: 127[Submi ...
- 【BZOJ2212】[Poi2011]Tree Rotations 线段树合并
[BZOJ2212][Poi2011]Tree Rotations Description Byteasar the gardener is growing a rare tree called Ro ...
- BZOJ 2212: [Poi2011]Tree Rotations( 线段树 )
线段树的合并..对于一个点x, 我们只需考虑是否需要交换左右儿子, 递归处理左右儿子. #include<bits/stdc++.h> using namespace std; #defi ...
- loj2163 / bzoj2212 / P3521 [POI2011]ROT-Tree Rotations(线段树合并)
P3521 [POI2011]ROT-Tree Rotations loj2163 [POI2011]ROT-Tree Rotations(数据加强) (loj的数据套了个fread优化才过...) ...
- 2212: [Poi2011]Tree Rotations
2212: [Poi2011]Tree Rotations https://www.lydsy.com/JudgeOnline/problem.php?id=2212 分析: 线段树合并. 首先对每个 ...
- 洛谷 P3521 [POI2011]ROT-Tree Rotations 解题报告
P3521 [POI2011]ROT-Tree Rotations 题意:递归给出给一棵\(n(1≤n≤200000)\)个叶子的二叉树,可以交换每个点的左右子树,要求前序遍历叶子的逆序对最少. 大体 ...
- POI2011 Tree Rotations
POI2011 Tree Rotations 给定一个n<=2e5个叶子的二叉树,可以交换每个点的左右子树.要求前序遍历叶子的逆序对最少. 由于对于当前结点x,交换左右子树,对于范围之外的逆序对 ...
- [bzoj3702/2212][Poi2011]二叉树/Tree Rotations_线段树
二叉树 Tree Rotations bzoj-3702 bzoj-2212 Poi-2011 题目大意:现在有一棵二叉树,所有非叶子节点都有两个孩子.在每个叶子节点上有一个权值(有n个叶子节点,满足 ...
- bzoj 2212 Tree Rotations
bzoj 2212 Tree Rotations 考虑一个子树 \(x\) 的左右儿子分别为 \(ls,rs\) .那么子树 \(x\) 内的逆序对数就是 \(ls\) 内的逆序对数,\(rs\) 内 ...
随机推荐
- MyBatis数据持久化(四)类型别名
Mybatis的类型别名指的是我们可以为Java类型自定义一个简短的名字,以达到简化配置的目的,在上篇博文中我们的sql语句配置文件内容如下: <?xml version="1.0&q ...
- 「JavaSE 重新出发」02. 数据类型与运算符
「TOC」 Java 程序基本要求 Java 数据类型 基本数据类型 复合数据类型 运算符 逻辑运算符 位运算符 运算符优先级 Java 程序基本要求 public class : 一个 Java 文 ...
- javascript中的正则示例
// 方式一var obj_re = new RegExp("\d+","gi"); //g 全局,i 不区分大小写obj_re.test("fasf ...
- 【BZOJ4016】【FJOI2014】最短路径树问题
题意: Description 给一个包含n个点,m条边的无向连通图.从顶点1出发,往其余所有点分别走一次并返回. 往某一个点走时,选择总长度最短的路径走.若有多条长度最短的路径,则选择经过的顶点序列 ...
- LightOJ-1259 Goldbach`s Conjecture 数论 素数筛
题目链接:https://cn.vjudge.net/problem/LightOJ-1259 题意 给一个整数n,问有多少对素数a和b,使得a+b=n 思路 素数筛 埃氏筛O(nloglogn),这 ...
- 使用vue实现简单键盘,支持移动端和pc端
常看到各种app应用中使用自定义的键盘,本例子中使用vue2实现个简单的键盘,支持在移动端和PC端使用,欢迎点赞,h5 ios输入框与键盘 兼容性优化 实现效果: Keyboard.vue <t ...
- 继续过Hard题目.周五
# Title Editorial Acceptance Difficulty Frequency . 65 Valid Number 12.6% Hard . 126 Word ...
- spark 针对决策树进行交叉验证
from pyspark import SparkContext, SQLContext from pyspark.ml import Pipeline from pyspark.ml.classif ...
- Git-如何将已存在的项目提交到git
1.首先在码云或者github上创建一个不带README.md的项目,然后复制远程库的地址(下面以码云为例): 2.进入本地已存在的项目目录:house touch README.md //新建说明 ...
- 83.导入项目时,用npm install安装module
npm install 正因为有了npm,我们只要一行命令,就能安装别人写好的模块 .