题面

传送门:[CQOI2011]动态逆序对


Solution

一开始我看到pty巨神写这套题的时候,第一眼还以为是个SB题:这不直接开倒车线段树统计就完成了吗?

然后冷静思考了一分钟,猛然发现单纯的线段树并不能解决这个问题,好像还要在外面再套上一颗树。

这就很shit了。你问我资磁不资磁树套树,我是不资磁的,树套树是暴力数据结构,我能资磁吗?

很不幸,昨天现实狠狠地打了我一脸:时间不够开新坑的,不切题又浑身难受,找了半天题,还是把这道题拉了出来(哈,真香)

不扯淡了,这题还是很显然的。

考虑开倒车,我们一个一个往里面加树,然后统计一下这个数能对当前的数列有多少贡献,贡献很容易想到:我们只需要找到在他后面比他小的数以及在他前面比他大的数就好。

然后本蒟蒻写了个蜜汁线段树套splay。

时间复杂度是$O(n*log^2n)$,空间复杂度为$O(n*logn)$。理论上应该能过

可惜现实非常苦感:

.....

那咋搞啊。

那我上个线段树套权值线段树吧

然后又码了半个小时。

时空复杂度均为$O(n*log^2n)$ (这明显要MLE啊,问题是题解蜜汁能过)

可惜现实依旧苦感:

难道,改数据了?

接着,我copy了一发题解,交上去,A掉了.......

到目前为止,我还是想不通为啥开同样的数组,他A了,我T了。难道说他外层套的树状数组可以有效减少空间的消耗?

想不通,还请个位dalao赐教。


Code (并不能A)

线段树套splay:

  1. #include<iostream>
  2. #include<cstdio>
  3. using namespace std;
  4. long long read()
  5. {
  6. long long x=0,f=1; char c=getchar();
  7. while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
  8. while(isdigit(c)){x=x*10+c-'0';c=getchar();}
  9. return x*f;
  10. }
  11. const int N=100000+1000;
  12. struct TreeInTree
  13. {
  14. #define mid ((now_l+now_r)>>1)
  15. #define lson (now<<1)
  16. #define rson (now<<1|1)
  17. #define root son[r][1]
  18. static const int M=N*25;
  19. int fa[M],son[M][2],size[M],cnt[M],num[M],to;
  20. inline void update(int x)
  21. {
  22. size[x]=size[son[x][0]]+size[son[x][1]]+cnt[x];
  23. }
  24. inline void rotate(int x,int type)
  25. {
  26. int y=fa[x],z=fa[y];
  27. son[z][y==son[z][1]]=x,fa[x]=z;
  28. son[y][!type]=son[x][type],fa[son[x][type]]=y;
  29. son[x][type]=y,fa[y]=x;
  30. update(y),update(x);
  31. }
  32. void splay(int x,int to)
  33. {
  34. while(fa[x]!=to)
  35. {
  36. if(x==son[fa[x]][fa[x]==son[fa[fa[x]]][1]] and fa[fa[x]]!=to)
  37. rotate(fa[x],x==son[fa[x]][0]);
  38. rotate(x,x==son[fa[x]][0]);
  39. }
  40. }
  41. void Insert(int w,int r)
  42. {
  43. if(root==0)
  44. {
  45. root=++to,fa[root]=r;
  46. num[root]=w,update(root);
  47. return;
  48. }
  49. int now=root,last=root;
  50. while(now!=0)
  51. last=now,now=son[now][w>num[now]];
  52. now=++to,fa[now]=last,son[last][w>num[last]]=now;
  53. num[now]=w,update(now);
  54. splay(now,r);
  55. }
  56. int Query1(int x,int r)
  57. {
  58. int now=root,ans=0;
  59. while(now!=0)
  60. {
  61. if(num[now]>=x)
  62. now=son[now][0];
  63. else
  64. {
  65. if(num[now]>num[ans]) ans=now;
  66. now=son[now][1];
  67. }
  68. }
  69. if(ans==0) return 0;
  70. splay(ans,r);
  71. return size[son[ans][0]]+cnt[ans];
  72. }
  73. int Query2(int x,int r)
  74. {
  75. int now=root,ans=0;
  76. num[0]=0x3f3f3f3f;
  77. while(now!=0)
  78. {
  79. if(num[now]>x)
  80. {
  81. if(num[now]<num[ans]) ans=now;
  82. now=son[now][0];
  83. }
  84. else
  85. now=son[now][1];
  86. }
  87. num[0]=0;
  88. if(ans==0) return 0;
  89. splay(ans,r);
  90. return size[son[ans][1]]+cnt[ans];
  91. }
  92. int t[N<<2];
  93. void Build(int now,int now_l,int now_r)
  94. {
  95. t[now]=++to;
  96. if(now_l==now_r) return;
  97. Build(lson,now_l,mid);
  98. Build(rson,mid+1,now_r);
  99. }
  100. inline void Insert2(int x,int w,int now,int now_l,int now_r)
  101. {
  102. Insert(w,t[now]);
  103. if(now_l!=now_r)
  104. {
  105. if(x<=mid) Insert2(x,w,lson,now_l,mid);
  106. else Insert2(x,w,rson,mid+1,now_r);
  107. }
  108. }
  109. int Query3(int l,int r,int w,int type,int now,int now_l,int now_r)
  110. {
  111. if(now_l>=l and now_r<=r)
  112. {
  113. if(type==1) return Query1(w,t[now]);
  114. else return Query2(w,t[now]);
  115. }
  116. int sum=0;
  117. if(l<=mid) sum+=Query3(l,r,w,type,lson,now_l,mid);
  118. if(r>mid) sum+=Query3(l,r,w,type,rson,mid+1,now_r);
  119. return sum;
  120. }
  121. #undef mid
  122. #undef lson
  123. #undef rson
  124. }tit;
  125. int n,m,p[N],q[N],unOK[N];
  126. long long ans[N];
  127. int main()
  128. {
  129. freopen("3157.in","r",stdin);
  130. freopen("3157.out","w",stdout);
  131.  
  132. int t=clock();
  133. n=read(),m=read();
  134. for(int i=1;i<=n;i++)
  135. p[read()]=i;
  136. for(int i=1;i<=m;i++)
  137. q[i]=read(),unOK[q[i]]=true;
  138.  
  139. tit.Build(1,1,n);
  140. for(int i=1;i<=n;i++)
  141. if(unOK[i]==false)
  142. {
  143. tit.Insert2(p[i],i,1,1,n);
  144. ans[m+1]+=tit.Query3(p[i],n,i,1,1,1,n)+tit.Query3(1,p[i],i,2,1,1,n);
  145. }
  146. for(int i=m;i>=1;i--)
  147. {
  148. tit.Insert2(p[q[i]],q[i],1,1,n);
  149. ans[i]=ans[i+1]+tit.Query3(p[q[i]],n,q[i],1,1,1,n)+tit.Query3(1,p[q[i]],q[i],2,1,1,n);
  150. }
  151.  
  152. for(int i=1;i<=m;i++)
  153. printf("%lld\n",ans[i]);
  154. cerr<<clock()-t<<endl;
  155. return 0;
  156. }

线段树套权值线段树

  1. #include<iostream>
  2. #include<cstdio>
  3. using namespace std;
  4. long long read()
  5. {
  6. long long x=0,f=1; char c=getchar();
  7. while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
  8. while(isdigit(c)){x=x*10+c-'0';c=getchar();}
  9. return x*f;
  10. }
  11. const int N=100000+1000;
  12. int n,m,p[N],q[N],unOK[N];
  13. long long ans[N];
  14. struct TreeInTree
  15. {
  16. #define mid ((now_l+now_r)>>1)
  17. #define lson (now<<1)
  18. #define rson (now<<1|1)
  19. static const int M=N*200;
  20. int son[M][2],num[M],to;
  21. inline void update(int x)
  22. {
  23. num[x]=num[son[x][0]]+num[son[x][1]];
  24. }
  25. void Insert(int x,int now,int now_l,int now_r)
  26. {
  27. if(now_l==now_r)
  28. {
  29. num[now]++;
  30. return;
  31. }
  32. if(now>to)
  33. cerr<<to;
  34. if(x<=mid)
  35. {
  36. if(son[now][0]==0) son[now][0]=++to;
  37. Insert(x,son[now][0],now_l,mid);
  38. }
  39. else
  40. {
  41. if(son[now][1]==0) son[now][1]=++to;
  42. Insert(x,son[now][1],mid+1,now_r);
  43. }
  44. update(now);
  45. }
  46. int Query1(int l,int r,int now,int now_l,int now_r)
  47. {
  48. if(l>r) return 0;
  49. if((now_l>=l and now_r<=r) or now==0)
  50. return num[now];
  51. int t_ans=0;
  52. if(l<=mid) t_ans+=Query1(l,r,son[now][0],now_l,mid);
  53. if(r>mid) t_ans+=Query1(l,r,son[now][1],mid+1,now_r);
  54. return t_ans;
  55. }
  56. int t[N<<2];
  57. void Build(int now,int now_l,int now_r)
  58. {
  59. t[now]=++to;
  60. if(now_l==now_r) return;
  61. Build(lson,now_l,mid);
  62. Build(rson,mid+1,now_r);
  63. }
  64. inline void Insert2(int x,int w,int now,int now_l,int now_r)
  65. {
  66. Insert(w,t[now],1,n);
  67. if(now_l!=now_r)
  68. {
  69. if(x<=mid) Insert2(x,w,lson,now_l,mid);
  70. else Insert2(x,w,rson,mid+1,now_r);
  71. }
  72. }
  73. int Query3(int l,int r,int w,int type,int now,int now_l,int now_r)
  74. {
  75. if(now_l>=l and now_r<=r)
  76. {
  77. if(type==1) return Query1(1,w-1,t[now],1,n);
  78. else return Query1(w+1,n,t[now],1,n);
  79. }
  80. int sum=0;
  81. if(l<=mid) sum+=Query3(l,r,w,type,lson,now_l,mid);
  82. if(r>mid) sum+=Query3(l,r,w,type,rson,mid+1,now_r);
  83. return sum;
  84. }
  85. #undef mid
  86. #undef lson
  87. #undef rson
  88. }tit;
  89. int main()
  90. {
  91. n=read(),m=read();
  92. for(int i=1;i<=n;i++)
  93. p[read()]=i;
  94. for(int i=1;i<=m;i++)
  95. q[i]=read(),unOK[q[i]]=true;
  96.  
  97. tit.Build(1,1,n);
  98. for(int i=1;i<=n;i++)
  99. if(unOK[i]==false)
  100. {
  101. tit.Insert2(p[i],i,1,1,n);
  102. ans[m+1]+=tit.Query3(p[i],n,i,1,1,1,n)+tit.Query3(1,p[i],i,2,1,1,n);
  103. }
  104. for(int i=m;i>=1;i--)
  105. {
  106. tit.Insert2(p[q[i]],q[i],1,1,n);
  107. ans[i]=ans[i+1]+tit.Query3(p[q[i]],n,q[i],1,1,1,n)+tit.Query3(1,p[q[i]],q[i],2,1,1,n);
  108. }
  109.  
  110. for(int i=1;i<=m;i++)
  111. printf("%lld\n",ans[i]);
  112. return 0;
  113. }

[Luogu P3157][CQOI2011]动态逆序对 (树套树)的更多相关文章

  1. luogu P3157 [CQOI2011]动态逆序对(CDQ分治)

    题目描述 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任务是在每次删除一个元素之前统计整个序列的逆序 ...

  2. Luogu P3157 [CQOI2011]动态逆序对

    题目链接 \(Click\) \(Here\) 这个题有点卡常数..我的常数比较大所以是吸着氧气跑过去的... 题意:计算对于序列中每个位置\(p\),\([1,p-1]\)区间内比它大的数的个数,和 ...

  3. LUOGU P3157 [CQOI2011]动态逆序对(CDQ 分治)

    传送门 解题思路 cdq分治,将位置看做一维,修改时间看做一维,权值看做一维,然后就转化成了三维偏序,用排序+cdq+树状数组.注意算删除贡献时要做两次cdq,分别算对前面和后面的贡献. #inclu ...

  4. P3157 [CQOI2011]动态逆序对(树状数组套线段树)

    P3157 [CQOI2011]动态逆序对 树状数组套线段树 静态逆序对咋做?树状数组(别管归并QWQ) 然鹅动态的咋做? 我们考虑每次删除一个元素. 减去的就是与这个元素有关的逆序对数,介个可以预处 ...

  5. [BZOJ 3295] [luogu 3157] [CQOI2011]动态逆序对(树状数组套权值线段树)

    [BZOJ 3295] [luogu 3157] [CQOI2011] 动态逆序对 (树状数组套权值线段树) 题面 给出一个长度为n的排列,每次操作删除一个数,求每次操作前排列逆序对的个数 分析 每次 ...

  6. P3157 [CQOI2011]动态逆序对

    P3157 [CQOI2011]动态逆序对 https://www.luogu.org/problemnew/show/P3157 题目描述 对于序列A,它的逆序对数定义为满足i<j,且Ai&g ...

  7. 洛谷 P3157 [CQOI2011]动态逆序对 解题报告

    P3157 [CQOI2011]动态逆序对 题目描述 对于序列\(A\),它的逆序对数定义为满足\(i<j\),且\(A_i>A_j\)的数对\((i,j)\)的个数.给\(1\)到\(n ...

  8. P3157 [CQOI2011]动态逆序对 (CDQ解决三维偏序问题)

    P3157 [CQOI2011]动态逆序对 题目描述 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一个排列,按照某种顺序依次删除m个元素,你的任 ...

  9. BZOJ_3295_[Cqoi2011]动态逆序对_CDQ分治+树状数组

    BZOJ_3295_[Cqoi2011]动态逆序对_CDQ分治+树状数组 Description 对于序列A,它的逆序对数定义为满足i<j,且Ai>Aj的数对(i,j)的个数.给1到n的一 ...

随机推荐

  1. 你来讲讲AQS是什么吧?都是怎么用的?

    前言 在Java面试的时候,多线程相关的知识是躲不掉的,肯定会被问.我就被问到了AQS的知识,就直接了当的问,AQS知道是什么吧,来讲讲它是怎么实现的,以及哪些地方用到了它.当时自己确实没有讲好,所以 ...

  2. 使用Commons FileUpload 1.3.3和Servlet 3.0上传文件

    简介 Commons FileUpload可以轻松地为web应用程序添加强大,高性能的文件上传功能.Servlet3.0之前的web应用程序需要使用Commons FileUpload组件上传文件,但 ...

  3. matplotlib绘图教程,设置标签与图例

    大家好,欢迎大家阅读周四数据处理专题,我们继续介绍matplotlib作图工具. 在上一篇文章当中我们介绍了matplotlib这个包当中颜色.标记和线条这三种画图的设置,今天我们同样也介绍三种新的设 ...

  4. C# Redis分布式锁 - 单节点

    为什么要用分布式锁? 先上一张截图,这是在浏览别人的博客时看到的. 在了解为什么要用分布式锁之前,我们应该知道到底什么是分布式锁. 锁按照不同的维度,有多种分类.比如 1.悲观锁,乐观锁; 2.公平锁 ...

  5. 第一次面试linux后台岗位

    今天给大家分享前段时间面试linux后台的面试题目,我从里面挑了几道大家比较陌生的题目,而且要那种手写代码的题目,这方面肯定很多人在实际面试时最怕的题目! 1.请说出如何用tcp服务实现文件的断点续传 ...

  6. 怀疑安装MySQL之后,导致OrCAD Capture、Allegro就打不开

    记得在异常出现之前,只安装了MySQL,之后OrCAD Capture.Allegro就打不开了. Capture.exe - 系统错误 allegro.exe - 系统错误 我尝试在Cadence的 ...

  7. 可能是东半球第二好用的软件工具全部在这里(update in 2020.10.09)

    1. 产品经理工具种草 浏览器:Google Chrome 网络浏览器 原型绘制软件:墨刀- 在线产品原型设计与协作平台(https://modao.cc/).摹客mockplus - 摹客,让设计和 ...

  8. 手把手教你AspNetCore WebApi:Serilog(日志)

    前言 小明目前已经把"待办事项"功能实现了,API文档也搞定了,但是马老板说过,绝对不能让没有任何监控的项目上线的. Serilog是什么? 在.NET使用日志框架第一时间会想到N ...

  9. gitlab-配置邮件

    一:配置邮件  1. 进入配置文件,通过修改/etc/gitlab/gitlab.rb来设置邮件功能  修改后的文件 1 ## GitLab URL 2 ##! URL on which GitLab ...

  10. 拉格朗日乘子法与KKT条件

    拉格朗日乘子法 \[min \quad f = 2x_1^2+3x_2^2+7x_3^2 \\s.t. \quad 2x_1+x_2 = 1 \\ \quad \quad \quad 2x_2+3x_ ...