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


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

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

举个例子,我们将序列$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. Activity-数据状态的保存

    由于手机是便捷式移动设备,掌握在用户的手中,它的展示方向我们是无法预知的,具有不确定性.平时我们拿着手机多数为竖屏,但有时候我们感觉累了也会躺着去使用手机,那么这时手机屏幕的展示方向可能已经被用户切换 ...

  2. oracle数据库的关闭

    数据库停止: shutdown normal 无新连接 等待当前会话结束 等待当前事务结束 强制检查点并关闭文件(一致性关闭) shutdown transactional 无新连接 结束当前会话 等 ...

  3. (转)Java 虚拟机体系结构

    来源:http://hxraid.iteye.com/blog/676235 众所周知,Java源代码被编译器编译成class文件.而并不是底层操作系统可以直接执行的二进制指令(比如Windows O ...

  4. 【转载·】Linux yum 安装 gcc 、gcc-c++

      2017年09月29日 22:45:54 上善若水 阅读数:6653更多 个人分类: Linux学习 所属专栏: Linux学习杂技   版权声明:本文为博主原创文章,未经博主允许不得转载. ht ...

  5. SCIP,Clp,Gurobi和Cplex安装

    SCIP安装 1.在自己的家目录下建立目录scip,并将获得的压缩包考入该文件夹并解压缩 tar -zxvf scipoptsuite-5.0.0.tgz 2.进入目录scipoptsuite-5.0 ...

  6. hook中ref使用

    hook使用ref 父组件: 引入                  useRef 声明ref的名字     const dateRef = useRef() 复值给组件         ref={d ...

  7. thymeleaf 拼接 超链接

    <dd><a th:href="@{/get/{id}(id=${user.id})}">基本资料</a></dd>

  8. OpenResty.spec

    Name: openresty Version: 1.13.6.1 Release: 2%{?dist} Summary: OpenResty, scalable web platform by ex ...

  9. hbase报错Could not initialize class org.apache.hadoop.hbase.protobuf.ProtobufUtil

    Caused by: java.lang.RuntimeException: java.io.IOException: java.lang.reflect.InvocationTargetExcept ...

  10. Android设置头像,手机拍照或从本地相冊选取图片作为头像

     [Android设置头像,手机拍照或从本地相冊选取图片作为头像] 像微信.QQ.微博等社交类的APP,通常都有设置头像的功能,设置头像通常有两种方式: 1,让用户通过选择本地相冊之类的图片库中已 ...