题目链接

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

然后,我们就可以对于每一个节点的两棵子树,求出其交换前与交换后的两棵子树内的逆序对个数,取最小就好啦!

怎么求啊,不能暴力吧,TLE啊,不会了呀!!! (ノ`⊿´)ノ(掀桌

对了,我们有线段树合并!(o゚▽゚)o

(如果不知道线段树合并是什么可以看这一篇文章哦。)

对于每一个叶节点,我们都可以建一棵权值线段树,然后一步一步合并上来,顺便求出两颗子树交换前和交换后的次数就好了。

一次线段树合并的时间复杂度就是两棵线段树之间重复节点的个数,由于这道题目的特殊性,所以两棵线段树之间重复节点的个数不会太多,总的时间复杂度就是O(nlogn)左右啦!(゚▽゚*)

代码:

#include<iostream>
#include<cstdio>
using namespace std;
//val存储每个节点的值,ls存储每个节点的左儿子编号 ,rs存储每个节点的右儿子编号
int n=0,tot=0,t=0,val[8000000],ls[8000000],rs[8000000];
long long ans=0,anon=0,antw=0;
int builnetre(int l,int r,int x)//建一棵新的线段树
{
val[++tot]=1;
if(l==r) return tot;
int mid=(l+r)>>1,nw=tot;
if(x<=mid) ls[nw]=builnetre(l,mid,x);
else rs[nw]=builnetre(mid+1,r,x);
return nw;
}
int mergtwtre(int l,int r,int x,int y)//合并两棵线段树
{
if(!x||!y) return (!x)?y:x;
if(l==r) { val[++tot]=val[x]+val[y]; return tot; }
int mid=(l+r)>>1,nw=++tot;
anon+=(long long)(val[rs[x]])*val[ls[y]];//anon为不交换的逆序对个数
antw+=(long long)(val[rs[y]])*val[ls[x]];//antw为交换后的逆序对个数
ls[nw]=mergtwtre(l,mid,ls[x],ls[y]);
rs[nw]=mergtwtre(mid+1,r,rs[x],rs[y]);
val[nw]=val[ls[nw]]+val[rs[nw]];
return nw;
}
int worea()
{
scanf("%d",&t);
if(t) return builnetre(1,n,t);
int nw=mergtwtre(1,n,worea(),worea());
ans+=min(anon,antw);//取最小累加
anon=antw=0;//注意:这个赋值语句不能放在合并函数之前,不然它们的值就会在下一层的合并中改变,就无法达到初始化的效果了
return nw;
}
int main()
{
scanf("%d",&n);
worea();
printf("%lld",ans);
return 0;
}

参考文章

Bzoj P2212 [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. 【BZOJ2212】[Poi2011]Tree Rotations 线段树合并

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

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

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

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

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

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

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

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

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

  8. [POI2011]ROT-Tree Rotations 线段树合并|主席树 / 逆序对

    题目[POI2011]ROT-Tree Rotations [Description] 现在有一棵二叉树,所有非叶子节点都有两个孩子.在每个叶子节点上有一个权值(有\(n\)个叶子节点,满足这些权值为 ...

  9. [bzoj2212]Tree Rotations(线段树合并)

    解题关键:线段树合并模板题.线段树合并的题目一般都是权值线段树,因为结构相同,求逆序对时,遍历权值线段树的过程就是遍历所有mid的过程,所有能求出所有逆序对. #include<iostream ...

随机推荐

  1. Django学习day13随堂笔记

    每日测验 """ 今日考题 1.什么是django中间件,它的作用是什么,如何自定义中间件,里面有哪些用户可以自定义的方法,这些方法有何特点 2.基于django中间件的 ...

  2. Git报错-refusing to merge unrelated histories

    执行git pull 时报错: 出现这个问题的最主要原因还是在于本地仓库和远程仓库实际上是独立的两个仓库.假如我之前是直接clone的方式在本地建立起远程github仓库的克隆本地仓库就不会有这问题了 ...

  3. Linux系列(34) - yum源文件(1)

    yum源文件各参数含义 在[/etc/yum.repos.d/]目录中,默认有4个yum源文件,其中[CentOS-Linux-BaseOS.repo]是基本yum源文件,如果我们能上网,那它是默认生 ...

  4. php stream 流封装协议

    http://php.net/manual/wrappers.php 过程: 1. 开始通信 2. 读取数据 3. 写入数据 4. 结束通信 usage: * 读写文件系统 <?php $han ...

  5. Windows环境下实现WireShark抓取HTTPS

    https 加密传输,Wireshark 没有设置的情况下是没有办法抓到包的 https 的数据包. 设置系统环境变量(SSLKEYLOGFILE) WireShark 设置 SSL 选项 参考文章: ...

  6. struts2 中 form-action action-form 的传参方式

    1.  struts2 Action获取表单提交数据 主要有三种方式: 1.1 使用ActionContext类 //获取actionContext对象 ActionContext context = ...

  7. str.strip(chars)

    strip会去除给定字符串的指定字符,指定字符可以是一个或多个,去除从左右分别进行,没有则忽略,如果需要去除某个中间的字符,必须先去除外围的字符 看几个例子,以s为例,故意设置为非对称结构, s = ...

  8. mybatis中#{}与${}取值的区别

    1. 首先对于一个接口 Employee getEmpByIdAndName(@Param("id") Integer id,@Param("empName") ...

  9. Jenkins持续集成与部署

    一.Jenkins简介 在阅读此文章之前,你需要对Linux.Docker.Git有一定的了解和使用,如果还未学习,请阅读我前面发布的相关文章进行学习. 1.概念了解:CI/CD模型 CI全名Cont ...

  10. C++学习 1 数组

    一维数组: 定义:1.数据类型 数组名 [ 数组长度 ]: int arr [5];//赋值 arr[0]=10; arr[1]=20; arr[2]=30; arr[3]=40; arr[4]=50 ...