P1908逆序对:从顺序表到树状数组

1 题目链接

洛谷P1908
本文参考的题解

2 顺序表解题思路

2.1 重要变量

  1. a数组:存储输入的元素
  2. s数组:用于记录元素加入逆序对统计过程的状态(可结合2.2的表格理解)。
  3. ans:记录当前逆序对的数量,初始化为0。
  4. ranks数组:存储输入的元素从小到大排序对应的序号。
    另外还需要定义结构体node,其成员变量有num和val。a数组是node类型的。

2.2 解题过程

  1. 在输入n个数时,no存储输入的顺序,val存储输入的值。
  2. 对a数组按照元素值从小到大排序,如果遇到元素值相同的情况,则输入顺序靠前的排在前面。
  3. 按照输入的顺序,获取每个元素的排序编号,以输入顺序为下标,存在ranks数组中。比如对于输入的6个数,5,1,2,6,3,1,则ranks[1]=5,ranks[2]=1,ranks[3]=3,ranks[4]=6,ranks[5]=4,ranks[6]=2。
  4. 遍历ranks数组的每个元素,根据表达式s[ranks[i]]=1,填数,过程如下:
    1)ranks[1]=5,所以s[5]=1,如下表所示。之后用变量tmp存储s[1]到s[5]填了1的格子数量,可知tmp=0。接着,我们用表达式 i - tmp表示填入第i个数位置有多少个数比第i个数大。然后将这个表达式结果加进ans中。可知当前ans = 0。
下标 1 2 3 4 5 6
数值 0 0 0 0 1 0

2)ranks[2]=1,所以s[1]=1,如下表所示。和1)一样,用i-tmp算出当前比第二个数大的数,表达式结果为1,更新ans的值,ans+=i-tmp=1。这里可以这样理解:如果我们把ranks里面的元素比作一群旅客住在宾馆的楼层(假设每层只住1人),每个旅客按照下标顺序入住,每个人想知道前面有多少人住的楼层比自己高,最后统计一个总和存储在ans中。对于第二个人住在1楼,他可以在上到自己的那层之前每层都去看一下,统计入住人数tmp。在这里ranks[2]=1,ranks[1]=5,所以2号旅客上到1楼入住后,他统计一下1楼之前及1楼只住了1个人,而他是第二个入住的,所以有一个人住的比他高。ans+=i-tmp=1.

下标 1 2 3 4 5 6
数值 1 0 0 0 1 0

3) ranks[3]=3,所以s[3]=1。同样,用2)中的例子来讲,第3个人住3楼,他也想知道有多少人住的比他高。所以在在上到自己的那层之前每层都去看一下,统计入住人数tmp=s[1]+s[2]+s[3]=2。而他是第3个入住的,所以ans+=i-tmp=2.

下标 1 2 3 4 5 6
数值 1 0 1 0 1 0

4) ranks[4]=6,所以s[6]=1。同样,第4个人住6楼,他也想知道有多少人住的比他高。所以在在上到自己的那层之前每层都去看一下,统计入住人数tmp=4。而他是第4个入住的,所以ans+=i-tmp=2.

下标 1 2 3 4 5 6
数值 1 0 1 0 1 1

5) ranks[5]=4,所以s[4]=1。同样,第5个人住4楼,他也想知道有多少人住的比他高。所以在在上到自己的那层之前每层都去看一下,统计入住人数tmp=3。而他是第5个入住的,所以ans+=i-tmp=4.

下标 1 2 3 4 5 6
数值 1 0 1 1 1 1

6) ranks[6]=2,所以s[2]=1。同样,第6个人住2楼,他也想知道有多少人住的比他高。所以在在上到2楼之前每层都去看一下,统计入住人数tmp=2。而他是第6个入住的,所以ans+=i-tmp=8.

下标 1 2 3 4 5 6
数值 1 1 1 1 1 1

按照这个过程去计算,最终样例的答案是8。

2.3 代码实现

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int s[500010],ranks[500010],n;
long long ans; 
struct point
{
   
   
    int num,val;
}a[
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值