3295: [Cqoi2011]动态逆序对
Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2263 Solved: 721
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
1
5
3
4
2
5
1
4
2
Sample Output
2
2
1
样例解释
(1,5,3,4,2)(1,3,4,2)(3,4,2)(3,2)(3)。
HINT
N<=100000 M<=50000
这道题显然是裸题,不过即使是裸题还是有一点点价值的,因为这种题的做法比较多,可以多练习下模板(捂脸)。
做法1:主席树,这个很显然,不用多说了,PS:因为M是N的一半,所以要静态建树,修改M次时再套用树状数组,空间复杂度是MlogNlogN,否则是NlogNlogN,会爆空间(不要问我为什么知道,我不想说=.=)
做法2:二维线段树,和主席树差不多啊,同样要注意空间问题。
做法3:树状数组套平衡树。如果平衡树选择的是Splay就要注意很多问题:同样要先静态求出答案,因为splay的常数比较大,同时插入的时候要打乱顺序,因为Splay若是插入有序的数列复杂度会退化(话说是不是我写的不对?)。所以比较好的选择是用Treap,常数很低,复杂度稳定,直接倒过来插入N个数就行了,简单粗暴,代码100行都不要(主席树和Splay的我写了150行)。
做法4:分块,这个代码就更短了,不过复杂度堪忧,Nsqrt(N)log(sqrt(N)),不过令人高兴的是BZOJ貌似是只看总时间的(?),所以可以水过,PS:分块的总时间看来并没有比前面几种算法慢,是数据水还是复杂度可以特殊分析?
做法5:显然后面的插入对前面的询问不会有影响,且这个问题的本质是计数问题,所以插入之间互相不影响效果,即每个插入对答案的贡献是独立的,所以我们可以采用按时间分治的算法,将操作(一个点的插入和询问可以分成两个)分成两部分,递归处理后再计算前半部分的插入对后半部分的查询造成的影响。那么我们将原问题转化为:
给定平面上一些点,再询问若干个点,回答询问的点左上角(右下角的可以分开来做,也可以合起来)(即坐标在他之前的,值比他大)有多少个点。那么我们此时将询问和给定点再看成一些操作并按X坐标排序,我们发现该问题仍然满足之前的性质,即X坐标大的插入不影响X坐标小的询问,那么我们再次运用按时间分治,将问题继续简化为:
给定一些数和一些询问数,对于每个询问回答比他大的数有多少个。显然若将询问和插入排好序,则可以线性回答,我们发现在分治时已经将该区间的左右分别排序,那么怎么得到这个区间的排序呢?这个问题是不是很熟悉,对!就是归并排序,同时归并排序的本质也就是按时间分治。
那么处理最后一个问题的复杂度就是O(N),同时我们套用了两层分治,总复杂度为NlogNlogN,由于分治的常数特别小,而且空间占用为O(N),所以该做法的空间,时间,编程复杂度均小于前面几种做法。(CDQ大法好,离线大法好)
至于代码呢,我当然是没有的,毕竟我这种人只会耍嘴炮=.=(这种模板题放了代码也没用吧,自己写一遍最好理解)