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. Ubuntu 15.04 双击运行 *.sh、*.py文件

    源 起 之前一直在Windows下用AndoridStudio,今天试了一下在Linux系统Ubuntu 15.04中配置Android Studio: 过程和Windws下差不多,但是最后没有生成桌 ...

  2. 【BZOJ】4259: 残缺的字符串 FFT

    [题意]给定长度为m的匹配串B和长度为n的模板串A,求B在A中出现多少次.字符串仅由小写字母和通配符" * "组成,其中通配符可以充当任意一个字符.n<=3*10^5. [算 ...

  3. python读写mysql

    读取mysql数据 # -*- coding: utf-8 -*- # 导入必要模块 import pandas as pd from sqlalchemy import create_engine ...

  4. CSS line-height与行内框

    一.line-height的定义 line-height,行高,是指文本行基线间的垂直距离. 1.    什么是基线? 一般而言,一个文本行一共有四条线,从上到下依次为顶线.中线.基线.底线:在英文中 ...

  5. 两个Bounding Box的IOU计算代码

    Bounding Box的数据结构为(xmin,ymin,xmax,ymax) 输入:box1,box2 输出:IOU值 import numpy as np def iou(box1,box2): ...

  6. 002_安装第三方APP好的站点及解除安全与隐私限制

    一.解除安全与隐私限制的任何来源. http://bbs.feng.com/read-htm-tid-10714286.html 接下来,我们就打开终端,然后输入以下命令:   sudo spctl ...

  7. [HBase]mem store flusher 流程

  8. 数据库--mysql介绍

    一:什么是数据库 数据库(Database)是按照数据结构来组织.存储和管理数据的仓库, 每个数据库都有一个或多个不同的API用于创建,访问,管理,搜索和复制所保存的数据. 我们也可以将数据存储在文件 ...

  9. GitHub如何使用

    先马克一下,有空看看:http://blog.csdn.net/xiahouzuoxin/article/details/9393119

  10. hdu 4642 翻硬币

    在一个n*m的棋盘上 每一个格子都有一枚硬币 1表示正面 0表示反面你每次可以选择一个硬币为正面的点,然后从该点与右下角点形成的矩阵硬币全都反向,直到一个人没有硬币可以选择则输Alice先手 列举了几 ...