题目大意是在能够改变两个数的位置的情况下计算逆序对数

这因为是动态记录逆序对

本来单纯逆序对只要用树状数组计算即可,但这里因为更新,所以利用TReap树的删点和增加点来进行更新

大致是把每个树状数组所管理的点都放在对应的Treap树下,

这样x-=lowbit(x)下来,正好访问到是所有比他小范围下的点了

然后根据每棵访问到的Treap树有多少个节点是比当前值小的即可

每次交换ai , aj , (i<j)只要考虑(i,j)范围内比ai大的数,比aj小的数,然后加加减减即可

如果ai!=aj也是要加减1

  1. #include <bits/stdc++.h>
  2.  
  3. using namespace std;
  4. #define N 20005
  5.  
  6. struct Node{
  7. int l , r , val , sz , pri , cnt;
  8. //cnt表示当前位置相同的数有多少个,pri表示优先级,sz表示这棵子树所含有的节点总个数
  9. Node(){
  10. l = r = ;
  11. cnt = sz = , pri = rand();
  12. val = ;
  13. }
  14. Node(int v){
  15. Node();
  16. val = v;
  17. }
  18. };
  19. #define ls node[x].l
  20. #define rs node[x].r
  21. namespace Treap{
  22. int tot;//Treap Node节点的总个数
  23. int A[N];//有n棵treap树,A[]表示每棵treap树的起始位置
  24. Node node[N*];
  25. void init(){
  26. node[] = Node();
  27. node[].cnt = node[].sz = ;
  28. memset(A , , sizeof(A));
  29. tot = ;
  30. }
  31. int newNode(int v){
  32. ++tot;
  33. node[tot].cnt = node[tot].sz = ;
  34. node[tot].l = node[tot].r = ;
  35. node[tot].pri = rand();
  36. node[tot].val = v;
  37. return tot;
  38. }
  39. void push_up(int x) {
  40. // cout<<"here: "<<x<<" "<<ls<<" "<<rs<<endl;
  41. if(x>)
  42. node[x].sz = node[ls].sz+node[rs].sz+node[x].cnt;
  43. }
  44. void rotL(int &x){
  45. int y = rs;
  46. rs = node[y].l;
  47. node[y].l = x;
  48.  
  49. push_up(x);
  50. push_up(y);
  51. x = y;
  52. }
  53. void rotR(int &x){
  54. int y = ls;
  55. ls = node[y].r;
  56. node[y].r = x;
  57.  
  58. push_up(x);
  59. push_up(y);
  60. x = y;
  61. }
  62. void insert(int &x , int v){
  63. // cout<<x<<" "<<v<<endl;
  64. if(x == ) x = newNode(v);
  65. else if(node[x].val>v){
  66. insert(ls , v);
  67. if(node[ls].pri>node[x].pri) rotR(x);
  68. }
  69. else if(node[x].val<v){
  70. insert(rs , v);
  71. if(node[rs].pri>node[x].pri) rotL(x);
  72. }
  73. else node[x].cnt++;
  74. push_up(x);
  75. // cout<<x<<" "<<v<<" "<<"endd"<<endl;
  76. }
  77. void erase(int &x , int v){
  78. if(x == ) return ;
  79. else if(v<node[x].val) erase(ls , v);
  80. else if(v>node[x].val) erase(rs , v);
  81. else {
  82. node[x].cnt--;
  83. if(node[x].cnt<=){
  84. if(ls==&&rs==) x = ;
  85. else if(ls == ) x = rs;
  86. else if(rs == ) x = ls;
  87. else{
  88. if(node[ls].pri <node[rs].pri) rotL(x),erase(ls,v);
  89. else rotR(x) , erase(rs , v);
  90. }
  91. }
  92. }
  93. push_up(x);
  94. }
  95. int getCnt(int x , int v){//从x号节点出发找到对应的子树下小于等于v的值的个数
  96. if(x == ) return ;
  97. int ans = ;
  98. if(node[x].val>v) ans = getCnt(ls , v);
  99. else if(node[x].val<v) ans = node[x].cnt+node[ls].sz+getCnt(rs , v);
  100. else ans = node[x].cnt+node[ls].sz;
  101. return ans;
  102. }
  103. }
  104. int n , m , h[N] , a[N] , tot;
  105. //树状数组部分
  106. #define lowbit(x) x&(-x)
  107. void Add(int id , int v)
  108. {
  109. for(int x=id ; x<=n ; x+=lowbit(x)){
  110. Treap::insert(Treap::A[x] , v);
  111. }
  112. }
  113. void Erase(int id , int v)
  114. {
  115. for(int x=id ; x<=n ; x+=lowbit(x)){
  116. Treap::erase(Treap::A[x] , v);
  117. }
  118. }
  119. int getSum(int p , int v)//cal 1~p区间内小于等于v的值的个数
  120. {
  121. int sum = ;
  122. for(int x=p ; x> ; x-=lowbit(x)){
  123. sum+=Treap::getCnt(Treap::A[x] , v);
  124. }
  125. return sum;
  126. }
  127. int getSumMin(int p , int v)//cal 1~p区间内小于v的值的个数
  128. {
  129. v--;//important保证等于的情况被排除
  130. return getSum(p , v);
  131. }
  132.  
  133. int main()
  134. {
  135. // freopen("a.in" , "r" , stdin);
  136. scanf("%d" , &n);
  137. for(int i= ; i<=n ; i++){
  138. scanf("%d" , &h[i]);
  139. a[i] = h[i];
  140. }
  141. sort(a+ , a+n+);
  142. tot = unique(a+ , a+n+)-(a+);
  143. Treap::init();
  144. int sum = ;
  145. for(int i= ; i<=n ; i++){
  146. h[i] = lower_bound(a+ , a+tot+ , h[i])-a;
  147. Add(i , h[i]);
  148. sum+=i--getSum(i- , h[i]);
  149. }
  150. printf("%d\n" , sum);
  151.  
  152. scanf("%d" , &m);
  153. while(m--){
  154. // for(int i=1 ; i<=n ; i++)
  155. // cout<<h[i]<<" ";
  156. // cout<<endl;
  157. int ai , bi;
  158. scanf("%d%d" , &ai , &bi);
  159. if(ai>bi) swap(ai , bi);
  160. if(h[ai]<h[bi]) sum++;
  161. else if(h[ai]>h[bi]) sum--;
  162. else{
  163. printf("%d\n" , sum);
  164. continue;
  165. }
  166. int add = ;
  167. if(bi-ai>){
  168. add += getSumMin(bi- , h[bi])-getSumMin(ai , h[bi]);
  169. add -= (bi-ai-)-(getSum(bi- , h[bi])-getSum(ai , h[bi]));
  170. add += (bi-ai-)-(getSum(bi- , h[ai])-getSum(ai , h[ai]));
  171. add -= getSumMin(bi- , h[ai])-getSumMin(ai , h[ai]);
  172. }
  173.  
  174. sum += add;
  175.  
  176. Erase(ai , h[ai]);
  177. Erase(bi , h[bi]);
  178. Add(ai , h[bi]);
  179. Add(bi , h[ai]);
  180. swap(h[ai] , h[bi]);
  181. printf("%d\n" , sum);
  182. }
  183. return ;
  184. }

bzoj2141 树状数组套Treap树的更多相关文章

  1. BZOJ - 3295 动态逆序对 (树状数组套treap)

    题目链接 思路和bzoj2141差不多,不过这道题的数据更强一些,线段树套treapT了,树状数组套treap卡过~~ #include<bits/stdc++.h> using name ...

  2. [bzoj3196][Tyvj1730]二逼平衡树_树套树_位置线段树套非旋转Treap/树状数组套主席树/权值线段树套位置线段树

    二逼平衡树 bzoj-3196 Tyvj-1730 题目大意:请写出一个维护序列的数据结构支持:查询给定权值排名:查询区间k小值:单点修改:查询区间内定值前驱:查询区间内定值后继. 注释:$1\le ...

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

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

  4. BZOJ 1901 Zju2112 Dynamic Rankings ——树状数组套主席树

    [题目分析] BZOJ这个题目抄的挺霸气. 主席树是第一时间想到的,但是修改又很麻烦. 看了别人的题解,原来还是可以用均摊的思想,用树状数组套主席树. 学到了新的姿势,2333o(* ̄▽ ̄*)ブ [代 ...

  5. BZOJ1901 - Dynamic Rankings(树状数组套主席树)

    题目大意 给定一个有N个数字的序列,然后又m个指令,指令种类只有两种,形式如下: Q l r k 要求你查询区间[l,r]第k小的数是哪个 C i t  要求你把第i个数修改为t 题解 动态的区间第k ...

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

    3110: [Zjoi2013]K大数查询 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1384  Solved: 629[Submit][Stat ...

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

    题目链接:BZOJ - 3196 题目分析 区间Kth和区间Rank用树状数组套线段树实现,区间前驱后继用线段树套set实现. 为了节省空间,需要离线,先离散化,这样需要的数组大小可以小一些,可以卡过 ...

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

    题目链接:BZOJ - 1901 题目分析 树状数组套线段树或线段树套线段树都可以解决这道题. 第一层是区间,第二层是权值. 空间复杂度和时间复杂度均为 O(n log^2 n). 线段树比树状数组麻 ...

  9. BZOJ_3196_Tyvj 1730 二逼平衡树_树状数组套主席树

    BZOJ_3196_Tyvj 1730 二逼平衡树_树状数组套主席树 Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作: 1.查询k在区间内的排 ...

随机推荐

  1. PHPExcel对于Excel中日期和时间类型的处理

    PHPExcel是一款优秀的处理Excel文件读写的开源PHP Library,能够给我们提供强大的Excel读写能力,本文针对Excel处理过程中关于日期和时间类型的处理进行深入的讨论.PHPExc ...

  2. XML文件解析

    eclipse新建源文件的文件夹,编译后和src文件夹中放在一起 源文件 源文件的配置文件 测试文件 源文件的测试文件 一般用maven进行管理的时候就是这样 如果是小项目的话可能就src和resou ...

  3. C++ STL之vector用法总结

    介绍 vector是表示可变大小数组的序列容器. 就像数组一样,vector也采用的连续存储空间来存储元素.也就是意味着可以采用下标对vector的元素进行访问,和数组一样高效.但是又不像数组,它的大 ...

  4. 两行代码搞定 JavaScript 的日期验证

    我们通常在 JavaScript 中验证日期,基本的思路大概是,先判断年月日是否有效,再判断当月是否有当日,比如一些月份没有 31 日,平年二月没有 29.30 日,闰年二月没有 30 日等等. 偶然 ...

  5. JAX-WS使用Handler Chain加工消息

    承前 本文的示例,是基于前一篇文章中的实例而改进的,如果想要运行本文的代码例子,需要先实现前一篇的代码. 前一篇文章JAX-WS开发WebService初级 Handler概念 在WebService ...

  6. 动态代理proxy与CGLib的区别

    什么是代理? 静态代理与动态代理 静态代理实例 JDK动态代理实例 CGLib 简介 CGLib 与JDK动态代理的区别 代理模式是Java中常见的一种模式,英文名字叫走Proxy或者Surrogat ...

  7. javascript中的事件冒泡、事件捕获和事件执行顺序

    谈起JavaScript的 事件,事件冒泡.事件捕获.阻止默认事件这三个话题,无论是面试还是在平时的工作中,都很难避免. DOM事件标准定义了两种事件流,这两种事件流有着显著的不同并且可能对你的应用有 ...

  8. Android 防止OOM优化

    1. Android2.x及以下的系统优化: Bitmap被解码后的像素被存储在Native Heap中, Dalvik Heap有个external计数,记录了Bitmap所占用的内存. 当 Dal ...

  9. 【转】Centos升级Python 2.7.12并安装pip、ipython

    Centos系统一般默认就安装有Python2.6.6版本,不少软件需要2.7以上的,通过包管理工具安装不了最新的版本,通过源码编译可以方便安装指定版本,只需要把下面版本的数字换成你想要的版本号. 1 ...

  10. 雅虎(yahoo)前端优化十四条军规

    第一条.尽可能的减少 HTTP 的请求数 (Make Fewer HTTP Requests ) http请求是要开销的,想办法减少请求数自然可以提高网页速度.常用的方法,合并css,js(将一个页面 ...