title: 线段树-最小逆序数

date: 2018-10-12 17:19:16

tags:

  • acm
  • 算法
  • 刷题

    categories:
  • ACM-线段树

概述

这是一道简单的线段树的题,,,当然还有很多其他的做法,,,甚至时暴力都可以,,,

用线段树主要是为了在练一练线段树的使用,,,而且这次,,我换了一种写线段树的方法,,,

貌似也是很多大佬都在用的一种写法,,,

之前一直用的入门时为了好理解的一种写法:节点用结构体node表示,,,并且为了理解还添了每一个节点所对应的左右边界,,,

但实际上,,这些信息是没有用的,,,或者说是多余的,,,直接在使用时计算或者直接作为函数的形参传递就行了,,,,

这样的写法代码量更加的少而写写起来也方便,,,占用的空间也少了些,,,

题目的分析

这道题不像之前做的线段树的题那样所维护的值就是最终要求的答案,,,而是中间的某一过程量,,,

首先,,题目的意思就是对于一个给定的数列 \(a_0 , a_1 , a_2 , ,,, ,a_{n-1}\),,,每次将第一个数移动到后面,,,这样一共有n种序列,,,然后对于每一种序列都有一个 逆序数 ,,问你在这些逆序数中最小的那个是多小,,,,

  • 这道题只要知道其中一个序列的逆序数,,它的相邻一个逆序数也就可以推出来,,,具体是这样的:

    \(当已知第i个序列的逆序数sum_i时,,\)

    \(第i+1个序列的逆序数为sum_{i+1}=sum_i + n - a[i] - 1 - a[i],,,,\)

    \(就是说当将第一个数移到最后前,,,\)

    \(它以前的逆序数有 a[i] 个所以要减去这些,,\)

    \(而当它被移到最后时,,,\)

    \(前面又多了 n - a[i] - 1 个,,,\)

    \(最后的sum就求出来了,,,\)

  • 当知道上面这个递推式后,,,我们的任务就是求出所输入出的数列的逆序数,,,然后再根据递推式找出最小的那一个输出就行了,,,

  • 对于求这个数列的逆序数用线段树的方法是,,,先建一个空的数,,,然后每输入一个数,,标记一下,,不过标记在最后的更新完成,,,先求出它之前所输入的所有数中比它大的数(也就是看这个数到n-1一共有几个出现在之前的输入中,,,也就是看标记的和),,,也就是以它构成的逆序列,,,然后把它加(标记)到这个树里(更新),,,可以看出如果把标记改为存放这个数,,纳闷这棵树的叶子节点就是排序好的1~n-1数列,,,,这一段画个图就好理解了,,,

实现

code:

#include <iostream>
#include <cstdio>
#include <cstdlib> using namespace std; #define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r const int maxn = 5005;
int sum[maxn << 2]; void pushup(int rt)
{
sum[rt] = sum[rt << 1] + sum[rt << 1 | 1];
}
void build(int rt , int l , int r)
{
sum[rt] = 0;
if(l == r)
return; int mid = (l + r) >> 1; build(lson);
build(rson);
pushup(rt);
}
void update(int rt , int l , int r , int loc)
{
if(l == r)
{
++sum[rt];
return;
} int mid = (l + r) >> 1;
if(loc <= mid) update(lson , loc);
else update(rson , loc);
pushup(rt);
}
int query(int rt , int l , int r , int L , int R)
{
if(L <= l && r <= R)
return sum[rt]; int mid = (l + r) >> 1; int ans = 0;
if(L <= mid) ans += query(lson , L , R);
if(R > mid) ans += query(rson , L , R);
return ans;
}
int a[maxn];
int main()
{
int n;
while(scanf("%d" , &n) != EOF)
{
build(1 , 0 , n); int sm = 0;
for(int i = 0; i < n; ++i)
{
scanf("%d" , &a[i]);
sm += query(1 , 0 , n - 1 , a[i] , n - 1);
update(1 , 0 , n - 1 , a[i]);
} int ret = sm;
for(int i = 0; i < n; ++i)
{
sm += n - a[i] - 1 - a[i];
ret = min(sm , ret);
}
printf("%d\n" , ret);
}
}

线段树-最小逆序数hdu1394的更多相关文章

  1. hdu 1394(线段树) 最小逆序数

    http://acm.hdu.edu.cn/showproblem.php?pid=1394 给出一列数组,数组里的数都是从0到n-1的,在依次把第一个数放到最后一位的过程中求最小的逆序数 线段树的应 ...

  2. HDU_1394_Minimum Inversion Number_线段树求逆序数

    Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java ...

  3. hdu 1394 线段树计算逆序数

    线段树计算逆序数的原理: 用线段树来统计已插入的数的个数(所以要保证最大的那个数不能太大,否则数组都开不了),然后每插入一个数,就查询比插入的数大的个数,累加即可. 这个题还有一个特点就是,题目给的是 ...

  4. 【线段树求逆序数】【HDU1394】Minimum Inversion Number

    题目大意: 随机给你全排列中的一个,但不断的把第一个数丢到最后去,重复N次,形成了N个排列,问你这N个排列中逆序数最小为多少 做法: 逆序数裸的是N^2 利用线段树可以降到NlogN 具体方法是插入一 ...

  5. 线段树求逆序数方法 HDU1394&amp;&amp;POJ2299

    为什么线段树能够求逆序数? 给一个简单的序列 9 5 3 他的逆序数是3 首先要求一个逆序数有两种方式:能够从头開始往后找比当前元素小的值,也能够从后往前找比当前元素大的值,有几个逆序数就是几. 线段 ...

  6. hdu1394 Minimum Inversion Number (线段树求逆序数&&思维)

    题目传送门 Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K ...

  7. HDU-1394 Minimum Inversion Number(线段树求逆序数)

    Minimum Inversion Number Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Ot ...

  8. HDU - 1394 Minimum Inversion Number (线段树求逆序数)

    Description The inversion number of a given number sequence a1, a2, ..., an is the number of pairs ( ...

  9. hdu 1394 (线段树求逆序数)

    <题目链接> 题意描述: 给你一个有0--n-1数字组成的序列,然后进行这样的操作,每次将最前面一个元素放到最后面去会得到一个序列,那么这样就形成了n个序列,那么每个序列都有一个逆序数,找 ...

随机推荐

  1. Spring Data JPA原生SQL查询

    package com.test.cms.dao.repository;import org.springframework.stereotype.Repository;import javax.pe ...

  2. 100baseT、100baseFX、1000base-SX、100/1000base-T

    100baseT.100baseFX.1000base-SX.100/1000base-T 100baseT.100baseFX都是100Mbps速率基带传输系统,唯一的不同是100baseT用的是双 ...

  3. 标准vim配置文件 带注释(适合C++编译)

    我的vim配置文件,适合大多数人习惯 """""""""""""&qu ...

  4. 【leetcode 简单】 第九十七题 快乐数

    写一个程序,输出从 1 到 n 数字的字符串表示. 1. 如果 n 是3的倍数,输出“Fizz”: 2. 如果 n 是5的倍数,输出“Buzz”: 3.如果 n 同时是3和5的倍数,输出 “FizzB ...

  5. 树形dp&&树的重心(D - Godfather POJ - 3107)

    题目链接:https://cn.vjudge.net/contest/277955#problem/D 题目大意:求树的重心(树的重心指的是树上的某一个点,删掉之后形成的多棵树中节点数最大值最小). ...

  6. tomcat发布html静态页面

    一.环境 在Linux系统安装JDK并配置环境变量,安装tomcat(在tomcat官网下载压缩包即可,我使用的是tomcat7 https://tomcat.apache.org/download- ...

  7. Floyd_Warshall算法

    Floyd_Warshall算法主要用于求解所有节点对的最短路径,代码如下: #include<iostream> using namespace std; #define Inf 655 ...

  8. trace spring

    package xx.com.aspect; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotati ...

  9. TCP/IP详解(整理)

    1.概述 路由器是在网络层进行联通,而网桥是在链路层联通不同的网络. IP层用ICMP来与其他主机或路由器交换错误报文和其他的重要信息.应用程序也可以访问ICMP,两个诊断工具:Ping和Tracer ...

  10. HTTP之二 http 301 和 302的区别

    1.什么是301转向?什么是301重定向? 301转向(或叫301重定向,301跳转)是当用户或搜索引擎向网站服务器发出浏览请求时,服务器返回的HTTP数据流中头信息(header)中的状态码的一种, ...