时间限制:1秒 内存限制:64M
【问题描述】
对于序列A[i],它的逆序对数定义为满足:i < j,且A[i] > A[j]的数对(i,j)的个数。
给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序对数。
【输入格式】
输入第一行包含两个整数n和m,即初始元素的个数和删除的元素个数。以下n行每行包含一个1到n之间的正整数,即初始排列。以下m行每行一个正整数,依次为每次删除的元素。
【输出格式】
输出包含m行,依次为删除每个元素之前,逆序对的个数。
【输入样例】
5 4
1
5
3
4
2
5
1
4
2
【输出样例】
5
2
2
1
【数据范围】
编号 1-2 3-4 5-6 7-8 9-10
n <=1000 <=30000 <=50000 <=60000 <=100000
m <=100 <=10000 <=20000 <=40000 <=50000
【来源】
(1,5,3,4,2) -> (1,3,4,2) -> (3,4,2) -> (3,2) -> (3)。
今天晚上一直在做这道题,做了几种方法出来,但时间复杂度各不相同,准确的说只是常数不同,但就是这个常数有2种方法看起来可以却要被卡住1~2个点。
第一种方法:树套树,常数极高,可能是因为我用的线段树套平衡树,线段树的常数大了点。
第二种:分块+排序,普通的分块方法,就按照要求,分成几块,然后块内排序。删除就找前面比他大的和后面比他小的就好。会卡常数一个点。
第三种:分块+bit,也是分块,而且这种方法也要优化才能过,用bit记录块内的值,bit[i][j]前i个块一共有多少个在j所属的范围内。这个前缀和的思想可以省很多时间。
第四种:CDQ分治,也要优化,优化了特别快,没有优化特别慢,最可怕的是不容易看出来优化在哪里。
第五种:持续化线段树:思想和分块加bit的优化版差不多。
这里我提供一下CDQ分治的代码(因为难想),一个优化了的,一个没优化的,其他代码就不给了,请读者自己好好写,都不难但是请主要细节。
#include<cstdlib>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>