题目链接:BZOJ - 2212

题目分析

子树 x 内的逆序对个数为 :x 左子树内的逆序对个数 + x 右子树内的逆序对个数 + 跨越 x 左子树与右子树的逆序对。

左右子树内部的逆序对与是否交换左右子树无关,是否交换左右子树取决于交换后 “跨越 x 左子树与右子树的逆序对” 是否会减小。

因此我们要求出两种情况下的逆序对数,使用线段树合并,对每个节点建一棵线段树,然后合并的同时就求出两种情况下的逆序对。

代码

#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm> using namespace std; inline void Read(int &Num)
{
char c = getchar();
while (c < '0' || c > '9') c = getchar();
Num = c - '0'; c = getchar();
while (c >= '0' && c <= '9')
{
Num = Num * 10 + c - '0';
c = getchar();
}
} typedef long long LL; inline LL gmin(LL a, LL b) {return a < b ? a : b;} const int MaxN = 400000 + 5, MaxNode = 4000000 + 5; int n, IndexT, Index, RT;
int A[MaxN], Tree[MaxN][2], Root[MaxN], T[MaxNode], Son[MaxNode][2]; LL Ans0, Ans1, Ans; void Read_Tree(int &x)
{
x = ++IndexT;
Read(A[x]);
if (A[x] != 0) return;
Read_Tree(Tree[x][0]);
Read_Tree(Tree[x][1]);
} inline void Update(int x)
{
T[x] = T[Son[x][0]] + T[Son[x][1]];
} void Insert(int &x, int s, int t, int Pos)
{
if (x == 0) x = ++Index;
if (s == t)
{
T[x] = 1;
return;
}
int m = (s + t) >> 1;
if (Pos <= m) Insert(Son[x][0], s, m, Pos);
else Insert(Son[x][1], m + 1, t, Pos);
Update(x);
} int Merge(int x, int y)
{
if (!x) return y;
if (!y) return x;
Ans0 += (LL)T[Son[x][1]] * (LL)T[Son[y][0]];
Ans1 += (LL)T[Son[x][0]] * (LL)T[Son[y][1]];
Son[x][0] = Merge(Son[x][0], Son[y][0]);
Son[x][1] = Merge(Son[x][1], Son[y][1]);
Update(x);
return x;
} void Solve(int x)
{
if (A[x]) return;
Solve(Tree[x][0]); Solve(Tree[x][1]);
Ans0 = Ans1 = 0;
Root[x] = Merge(Root[Tree[x][0]], Root[Tree[x][1]]);
Ans += gmin(Ans0, Ans1);
} int main()
{
scanf("%d", &n);
Read_Tree(RT);
for (int i = 1; i <= IndexT; ++i)
if (A[i] != 0) Insert(Root[i], 1, n, A[i]);
Solve(RT);
cout << Ans << endl;
return 0;
}

  

[BZOJ 2212] [Poi2011] Tree Rotations 【线段树合并】的更多相关文章

  1. BZOJ.2212.[POI2011]Tree Rotations(线段树合并)

    题目链接 \(Description\) 给定一棵n个叶子的二叉树,每个叶节点有权值(1<=ai<=n).可以任意的交换两棵子树.问最后顺序遍历树得到的叶子权值序列中,最少的逆序对数是多少 ...

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

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

  3. Bzoj P2212 [Poi2011]Tree Rotations | 线段树合并

    题目链接 通过观察与思考,我们可以发现,交换一个结点的两棵子树,只对这两棵子树内的节点的逆序对个数有影响,对这两棵子树以外的节点是没有影响的.嗯,然后呢?(っ•̀ω•́)っ 然后,我们就可以对于每一个 ...

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

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

  5. bzoj2212[Poi2011]Tree Rotations [线段树合并]

    题面 bzoj ans = 两子树ans + min(左子在前逆序对数, 右子在前逆序对数) 线段树合并 #include <cstdio> #include <cstdlib> ...

  6. BZOJ2212 [Poi2011]Tree Rotations 线段树合并 逆序对

    原文链接http://www.cnblogs.com/zhouzhendong/p/8079786.html 题目传送门 - BZOJ2212 题意概括 给一棵n(1≤n≤200000个叶子的二叉树, ...

  7. bzoj2212/3702 [Poi2011]Tree Rotations 线段树合并

    Description Byteasar the gardener is growing a rare tree called Rotatus Informatikus. It has some in ...

  8. BZOJ_2212_[Poi2011]Tree Rotations_线段树合并

    BZOJ_2212_[Poi2011]Tree Rotations_线段树合并 Description Byteasar the gardener is growing a rare tree cal ...

  9. bzoj 2212 : [Poi2011]Tree Rotations (线段树合并)

    题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2212 思路:用线段树合并求出交换左右儿子之前之后逆序对的数量,如果数量变小则交换. 实现 ...

随机推荐

  1. [转]Oracle 调用存储过程并显示结果集 Oracle.DataAccess.Client OracleDbType.RefCursor

    本文转自:http://liye9801.blog.163.com/blog/static/6019703200901244448950/ 今天学习了一个Oracle中的存储过程,一开始便被如果返回结 ...

  2. Java接口的表现形式

    一.概念理解 Java接口是一些方法特征的集合,并没有方法的具体实现,类似于电源插座,可以充不同类型的电器,但是必须适配特定的接口规范.接口是抽象化的,所以其不能被实例化的(不能有构造函数,创建对象) ...

  3. asp.net服务器页面处理过程

    一.静态页面.动态页面区别 静态页面是服务端直接从硬盘里面读取然后发回去,动态页面就要创建这个页面类的对象,调用对象的方法,方法里面什么就发回什么.浏览器请求asp.net页面实际是请求asp.net ...

  4. android webview乱码问题

    使用 loadData方法是中文部分会出现乱码,即使指定“utf-8”.“gbk”.“gb2312”也一样. webView.getSettings().setDefaultTextEncodingN ...

  5. 第六篇、git常用的命令

    1.oscine git服务器地址 https://git.oschina.net/ 2.帐号:18775134221@163.com 密码:562011 3.创建私有的仓库 4.使用命令 4.1 配 ...

  6. Android笔记之adb命令解析1

    要在cmd命令中直接使用adb,需要配置环境变量:目录XXX\sdk\platform-tools 查看adb -help 帮助命令打印出以下内容: Android Debug Bridge vers ...

  7. [xUnit]尝试单元测试

    参考: http://xunit.github.io/ http://shouldly.readthedocs.org/en/latest/ 创建测试项目工程,类型选择类库,在NuGet中搜索xuni ...

  8. 用VIM写作

    Write in VIm 1.Writing in Vim by Dr. Bunsen

  9. C++ 遇见的一些函数

    1.位与(&)操作,计算十进制数中的为"1"的位数 int cnt_one(int k) { ; //保存位为"1"的数量 while (k) { k ...

  10. 4.MySQL连接并选择数据库(SQL & C)

    在连接了MySQL数据库之后,可以通过SQL命令或者C.PHP.JAVA等程序来指定需要操作的数据库.这里主要介绍SQL命令和相应的C程序. 首先创建用户rick(赋予所有权限) mysql> ...