Bestcoder7(1004)hdu4988(经典问题:树状数组套treap求解动态逆序对)

Little Pony and Boast Busters

Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)

Total Submission(s): 83    Accepted Submission(s): 32

Problem Description

"I hereby challenge you, Ponyvillians: anything you can do, I can do better. Any takers? Anyone? Or is Trixie destined to be the greatest equine who has ever lived!?!" — "Boast Busters"

Given two permutation P0 && P1 of {0, 1, ..., n - 1}, we define the crossing number of it as follows. Write P0 from left to right above P1 and draw a straight line between each same elements. The crossing number of
P0 and P1 is the number of pairs of lines that cross.

For example, if n = 5, and P0 = {0, 1, 2, 3, 4}, and P1 = {1, 3, 0, 2, 4}, then the crossing number of P0 and P1 is 3, as shown in the figure below.

Now given you the two permutation, you need to implement the following operations:

SWAP p a b: swap Pp[a] and Pp[b] (0<=p<=1, 0<=a, b<=n-1).

QUERY: ask the crossing number of the current P0 and P1.

Input

Input contains multiple test cases (less than 10). For each test case, the first line contains one integer n (1<=n<=10^5).

The second line contains n integers P0[0], P0[1], ..., P0[n-1].

The third line contains n integers P1[0], P1[1], ..., P1[n-1].

The next line contains one integer q —— the number of operations (1<=q<=10^5). The next q line, each line will contains a operation as we mentioned above.

Output

For each query, output the corresponding result in one line.

Sample Input

5
0 1 2 3 4
1 3 0 2 4
5
QUERY
SWAP 1 2 4
QUERY
SWAP 0 2 4
QUERY

Sample Output

3
6
5

Source

BestCoder Round #7

题意:给出两个0到n-1的排列,然后支持两种操作,QUERY查询两组排列的交叉的元素个数,SWAP 交换一个排列中两个位置的元素

思路:这题最后可以转化为给出一个排列P(将给出的两个排列的位置一一对应起来,参见大神的题解http://bestcoder.hdu.edu.cn),

可以动态交换P的任意两个位置的数,然后查询整个序列的逆序对数

动态逆序对是比较经典的树套树模型,我这里用的是树状数组套treap实现的,之前用的线段树妥妥的超时了

可以先用树状或归并排序求出初始序列的逆序对数,记为ans,然后每次查询只需要输出ans即可

重点在于交换,因为交换以后ans会随之改变,假设现在要交换L,R位置的数,那么[0,L-1],[R+1,n-1]这些位置的数是不用考虑的,因为它们对中间

元素的逆序对的贡献是不会改变的,所以只用考虑[L+1,R-1]之间的数

假设元素P[L] > P[R] ,设区间[L+1,R-1]的数小于P[L]的个数为L1,大于的个数为L2,同理设小于P[R]的个数为R1,大于的个数为R2,那么交换后的

答案 为ans = ans + L2-L1 + R1-R2 = ans + R1+L2 - (L1+R2),现在只需求出 R1 + L2 问题即可完美解决,因为L1+R2=2*n-(R1+L2) ,其中n为区间

[L+1,R-1]的元素个数,现在令区间[L+1,R-1]为S

而求R1等价于求S中元素小于P[R]的个数,求L2等价于求S中元素大于P[L]的个数,所以只需要在树状数组里套一个treap,用来维护该树状数组管辖的

区间的元素,具体涉及两种操作:

1.交换元素,相当于先将原位置的数删除,再在新的位置插入,这个就是树状数组单点更新了

2.查询一段区间中所有小于(大于)x的元素个数,相当于区间求和

怎么样,难点全部攻破了吧,这题也是把我写的醉到不行,调了许久才发现竟然树状数组没有初始化,sad~,累觉不爱,可以睡觉去了

时间: 2024-08-04 22:36:48

Bestcoder7(1004)hdu4988(经典问题:树状数组套treap求解动态逆序对)的相关文章

归并排序,树状数组 两种方法求逆序对

我们知道,求逆序对最典型的方法就是树状数组,可是另一种方法就是Merge_sort(),即归并排序. 实际上归并排序的交换次数就是这个数组的逆序对个数,为什么呢? 我们能够这样考虑: 归并排序是将数列a[l,h]分成两半a[l,mid]和a[mid+1,h]分别进行归并排序,然后再将这两半合并起来. 在合并的过程中(设l<=i<=mid,mid+1<=j<=h).当a[i]<=a[j]时.并不产生逆序数:当a[i]>a[j]时.在 前半部分中比a[i]大的数都比a[j]

bzoj2141 树状数组套Treap树

题目大意是在能够改变两个数的位置的情况下计算逆序对数 这因为是动态记录逆序对 本来单纯逆序对只要用树状数组计算即可,但这里因为更新,所以利用TReap树的删点和增加点来进行更新 大致是把每个树状数组所管理的点都放在对应的Treap树下, 这样x-=lowbit(x)下来,正好访问到是所有比他小范围下的点了 然后根据每棵访问到的Treap树有多少个节点是比当前值小的即可 每次交换ai , aj , (i<j)只要考虑(i,j)范围内比ai大的数,比aj小的数,然后加加减减即可 如果ai!=aj也是

BZOJ3295 动态逆序对 树套树, 树状数组套线段树(主席树)

Orz黄学长,蒟蒻在黄学长的带领下,通过阅读黄学长的代码!终于会了这道题! 首先我想先说一下这道题的思路(准确来说是黄学长的). 很明显,树状数组应该不用讲吧!关键是内存怎么开,维护一些什么样的数据? 其实我们通过观察,很快可以发现,你维护被删的数比维护所有的数轻松多了(不管是空间上,还是时间上).所以我们就可以从这方面想!(其实我一开始的思路,因为这道题我已经看过很久了,一直想写,毕竟是白书里面的一道例题嘛!一开始,蒟蒻的我是打算这样的用树状数组套权值线段树,并且是维护所有的数,我发现空间不够

3110: [Zjoi2013]K大数查询 树状数组套线段树

3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1384  Solved: 629[Submit][Status] Description 有N个位置,M个操作.操作有两种,每次操作如果是1 a b c的形式表示在第a个位置到第b个位置,每个位置加入一个数c如果是2 a b c形式,表示询问从第a个位置到第b个位置,第C大的数是多少. Input 第一行N,M接下来M行,每行形如1 a b c或2 a b

BZOJ 3196 Tyvj 1730 二逼平衡树 ——树状数组套主席树

[题目分析] 听说是树套树.(雾) 怒写树状数组套主席树,然后就Rank1了.23333 单点修改,区间查询+k大数查询=树状数组套主席树. [代码] #include <cstdio> #include <cstring> #include <cstdlib> #include <cmath> #include <set> #include <map> #include <string> #include <alg

[BZOJ 3196] 二逼平衡树 树状数组套主席树

3196: Tyvj 1730 二逼平衡树 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3357  Solved: 1326[Submit][Status][Discuss] Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的前驱(前驱定义为小于x,且最大的数)5.查询k在区间内的后继(后继定义为

【BZOJ】1047: [HAOI2007]理想的正方形(单调队列/~二维rmq+树状数组套树状数组)

http://www.lydsy.com/JudgeOnline/problem.php?id=1047 树状数组套树状数组真心没用QAQ....首先它不能修改..而不修改的可以用单调队列做掉,而且更快,只有O(n^2).而这货是n^2log^2n的建树...虽然查询是log^2n...但是建树那里就tle了.. 那么说题解... 先orz下,好神.. 我怎么没想到单调队列orz 首先我们维护 行 的单调队列,更新每个点在 列 距离内的最小and最大的值 然后我们维护 列 的单调队列,更新每个点

[BZOJ 3196] 213平衡树 【线段树套set + 树状数组套线段树】

题目链接:BZOJ - 3196 题目分析 区间Kth和区间Rank用树状数组套线段树实现,区间前驱后继用线段树套set实现. 为了节省空间,需要离线,先离散化,这样需要的数组大小可以小一些,可以卡过128MB = = 嗯就是这样,代码长度= =我写了260行......Debug了n小时= = 代码 #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #in

[BZOJ 1901] Dynamic Rankings 【树状数组套线段树 || 线段树套线段树】

题目链接:BZOJ - 1901 题目分析 树状数组套线段树或线段树套线段树都可以解决这道题. 第一层是区间,第二层是权值. 空间复杂度和时间复杂度均为 O(n log n). 代码 树状数组套线段树 #include <iostream> #include <cstdlib> #include <cstdio> #include <cmath> #include <algorithm> #include <cstring> usin