题目传送门

题目大意

有\(n\)个数,\(m\)个查询,每次查询一个区间内的逆序对个数。

\(n,m\le 10^5\)

思路

其实是为了锻炼二次离线才做这道题的。

不难想到可以有一个\(\Theta(n\sqrt n\log n)\)的方法,即用莫队,每次用树状数组计算变化的贡献。

然后我们就可以想到二次离线了。我们考虑计算\([l,r]\to [l,r^{'}]\)的贡献,可以发现\([l,r]\to[l,r+1]\)变换的贡献就是\([l,r]\)中比\(a_{r+1}\)大的个数,差分一下,就是\([1,r]\)中比\(a_{r+1}\)大的个数减去\([1,l-1]\)中比\(a_{r+1}\)大的个数。我们发现前面那个东西可以\(\Theta(n\log n)\)预处理出来,后面那个东西可以再次离线下来用值域分块\(\Theta(n\sqrt n)\)求出来。

我们再来考虑\([l,r]\to [l^{'},r]\)的变化。\([l,r]\to [l-1,r]\)的贡献就是\([l,r]\)中比\(a_{l-1}\)小的个数,差分一下,即是\([l,n]\)中比\(a_{l-1}\)小的个数减去\([r+1,n]\)中比\(a_{l-1}\)小的个数。前面那个东西同样可以离线\(\Theta(n\log n)\),后面那个也可以\(\Theta(n\sqrt n)\)值域分块。

于是,我们的总时间复杂度即为\(\Theta(m\sqrt n+n\sqrt n)\)。

但是这道题非常卡常。

\(\texttt{Code}\)

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define Int register int
  4. #define ll long long
  5. #define MAXN 100005
  6. #define MAXM 355
  7. ll ans[MAXN],sum1[MAXN],sum2[MAXN];
  8. int n,m,un,tot,siz,h[MAXN],w[MAXN],bel[MAXN],tmp[MAXN],laz[MAXM],col[MAXM],cor[MAXM],tree[MAXN];
  9. struct Query{
  10. int l,r,id;
  11. bool operator < (const Query &p)const{return (l / siz) != (p.l / siz) ? l < p.l : r < p.r;}
  12. }q[MAXN];
  13. struct node{int p,l,r,id;};
  14. vector <node> vec1[MAXN],vec2[MAXN];
  15. void add1 (int i,int p,int l,int r,int id){vec1[i].push_back (node {p,l,r,id});}
  16. void add2 (int i,int p,int l,int r,int id){vec2[i].push_back (node {p,l,r,id});}
  17. int lowbit (int x){return x & (-x);}
  18. void update (int x,int k){for (;x <= n;x += lowbit (x)) tree[x] += k;}
  19. int query (int x){int sum = 0;for (;x;x -= lowbit (x)) sum += tree[x];return sum;}
  20. void pushup1 (int x){
  21. if (laz[bel[x]]) for (Int i = col[bel[x]];i <= cor[bel[x]];++ i) w[i] += laz[bel[x]];laz[bel[x]] = 0;
  22. for (Int i = col[bel[x]];i <= x;++ i) w[i] ++;
  23. for (Int i = 1;i < bel[x];++ i) laz[i] ++;
  24. }
  25. void pushup2 (int x){
  26. if (laz[bel[x]]) for (Int i = col[bel[x]];i <= cor[bel[x]];++ i) w[i] += laz[bel[x]];laz[bel[x]] = 0;
  27. for (Int i = x;i <= cor[bel[x]];++ i) w[i] ++;
  28. for (Int i = bel[x] + 1;i <= tot;++ i) laz[i] ++;
  29. }
  30. void solve (){//二次离线部分
  31. int cnt = sqrt (un);col[tot = 1] = 1;
  32. if (cnt * cnt < un) ++ cnt;
  33. for (Int i = 1;i <= un;++ i){
  34. bel[i] = tot;
  35. if (i % cnt == 0) cor[tot] = i,col[++ tot] = i + 1;
  36. }
  37. cor[tot] = un;
  38. for (Int i = 1;i <= n;++ i){
  39. for (Int j = 0,len = vec1[i].size();j < len;++ j){
  40. int id = vec1[i][j].id,p = vec1[i][j].p;
  41. for (Int k = vec1[i][j].l;k <= vec1[i][j].r;++ k) ans[id] += 1ll * p * (laz[bel[h[k] + 1]] + w[h[k] + 1]);
  42. }
  43. pushup1 (h[i]);
  44. }
  45. for (Int i = 1;i <= tot;++ i) laz[i] = 0;
  46. for (Int i = 1;i <= un + 1;++ i) w[i] = 0;
  47. for (Int i = n;i >= 1;-- i){
  48. for (Int j = 0,len = vec2[i].size();j < len;++ j){
  49. int id = vec2[i][j].id,p = vec2[i][j].p;
  50. for (Int k = vec2[i][j].l;k <= vec2[i][j].r;++ k) ans[id] += 1ll * p * (laz[bel[h[k] - 1]] + w[h[k] - 1]);
  51. }
  52. pushup2 (h[i]);
  53. }
  54. }
  55. template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;}
  56. template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);}
  57. template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');}
  58. signed main(){
  59. read (n,m),siz = 317;
  60. for (Int i = 1;i <= n;++ i) read (h[i]),tmp[i] = h[i];
  61. sort (tmp + 1,tmp + n + 1);un = unique (tmp + 1,tmp + n + 1) - tmp - 1;
  62. for (Int i = 1;i <= n;++ i) h[i] = lower_bound (tmp + 1,tmp + un + 1,h[i]) - tmp;
  63. for (Int i = 1;i <= m;++ i) read (q[i].l,q[i].r),q[i].id = i;sort (q + 1,q + m + 1);
  64. for (Int i = 1;i <= n;++ i) sum1[i] = sum1[i - 1] + i - 1 - query (h[i]),update (h[i],1);
  65. for (Int i = 1;i <= n;++ i) tree[i] = 0;
  66. for (Int i = n;i;-- i) sum2[i] = sum2[i + 1] + query (h[i] - 1),update (h[i],1);
  67. int l = 1,r = 0;
  68. for (Int i = 1;i <= m;++ i){
  69. if (r < q[i].r) ans[q[i].id] += sum1[q[i].r] - sum1[r],add1 (l,-1,r + 1,q[i].r,q[i].id),r = q[i].r;
  70. if (r > q[i].r) ans[q[i].id] -= sum1[r] - sum1[q[i].r],add1 (l,1,q[i].r + 1,r,q[i].id),r = q[i].r;
  71. if (l < q[i].l) ans[q[i].id] -= sum2[l] - sum2[q[i].l],add2 (r,1,l,q[i].l - 1,q[i].id),l = q[i].l;
  72. if (l > q[i].l) ans[q[i].id] += sum2[q[i].l] - sum2[l],add2 (r,-1,q[i].l,l - 1,q[i].id),l = q[i].l;
  73. }
  74. solve ();
  75. for (Int i = 1;i <= m;++ i) ans[q[i].id] += ans[q[i - 1].id];
  76. for (Int i = 1;i <= m;++ i) write (ans[i]),putchar ('\n');
  77. return 0;
  78. }

题解 Yuno loves sqrt technology II的更多相关文章

  1. 有关二次离线和 Yuno loves sqrt technology II

    二次离线 前置技能 莫队 修改查询 \(O(\sqrt n )-O(1)\) 平衡 概念 考虑朴素莫队离线询问,过程中维护信息从 \([l,r]\) 扩展为 \([l\pm 1,r\pm 1]\) , ...

  2. [Ynoi2019模拟赛]Yuno loves sqrt technology II

    题目大意: 给定一个长为\(n\)的序列,\(m\)次询问,每次查询一个区间的逆序对数. 32MB. 解题思路: 出题人题解 众所周知lxl是个毒瘤,Ynoi道道都是神仙题 二次离线莫队. 对于每个区 ...

  3. [Ynoi2019模拟赛]Yuno loves sqrt technology II(二次离线莫队)

    二次离线莫队. 终于懂了 \(lxl\) 大爷发明的二次离线莫队,\(\%\%\%lxl\) 二次离线莫队,顾名思义就是将莫队离线两次.那怎么离线两次呢? 每当我们将 \([l,r]\) 移动右端点到 ...

  4. [洛谷P5048][Ynoi2019模拟赛]Yuno loves sqrt technology III

    题目大意:有$n(n\leqslant5\times10^5)$个数,$m(m\leqslant5\times10^5)$个询问,每个询问问区间$[l,r]$中众数的出现次数 题解:分块,设块大小为$ ...

  5. [Ynoi2019模拟赛]Yuno loves sqrt technology I

    题目描述 给你一个长为n的排列,m次询问,每次查询一个区间的逆序对数,强制在线. 题解 MD不卡了..TMD一点都卡不动. 强制在线的话也没啥好一点的方法,只能分块预处理了. 对于每个块,我们设lef ...

  6. [Ynoi2019模拟赛]Yuno loves sqrt technology III

    题目大意: 给你一个长为n的序列a,m次询问,每次查询一个区间的众数的出现次数,强制在线. 解题思路: 出题人题解 众所周知lxl是个毒瘤,Ynoi道道都是神仙题 首先得离散化. 分块后,预处理Fi, ...

  7. [Luogu5048] [Ynoi2019模拟赛]Yuno loves sqrt technology III[分块]

    题意 长为 \(n\) 的序列,询问区间众数,强制在线. \(n\leq 5\times 10^5\). 分析 考虑分块,暴力统计出整块到整块之间的众数次数. 然后答案还可能出现在两边的两个独立的块中 ...

  8. [luogu5048] [Ynoi2019模拟赛] Yuno loves sqrt technology III

    题目链接 洛谷. Solution 思路同[BZOJ2724] [Violet 6]蒲公英,只不过由于lxl过于毒瘤,我们有一些更巧妙的操作. 首先还是预处理\(f[l][r]\)表示\(l\sim ...

  9. 洛谷P5048 [Ynoi2019模拟赛]Yuno loves sqrt technology III(分块)

    传送门 众所周知lxl是个毒瘤,Ynoi道道都是神仙题 用蒲公英那个分块的方法做结果两天没卡过去→_→ 首先我们分块,预处理块与块之间的答案,然后每次询问的时候拆成整块和两边剩下的元素 整块的答案很简 ...

随机推荐

  1. SpringSecurity入门

    基础 spring security的底层就是一个过滤器链 ExceptionTranslationFilter是一个异常过滤器,用来处理认证授权过程中的异常 UseranmePasswordAuth ...

  2. 🏆【JVM技术专区】「难点-核心-遗漏」TLAB内存分配+锁的碰撞(技术串烧)!

    JVM内存分配及申请过程 当使用new关键字或者其他任何方式进行创建一个类的对象时,JVM虚拟机需要为该对象分配内存空间,而对象的大小在类加载完成后已经确定了,所以分配内存只需要在Java堆中划分出一 ...

  3. JavaScript 特殊字符

    代码输出\'单引号\"双引号\&和号\\反斜杠\n换行符\r回车符\t制表符\b退格符\f换页符

  4. QT学习日记篇01(1)-QT界面初探- *.pro文件详解

    一: 项目管理文件(.pro文件) 项目管理文件用于记录项目的一些设置,以及项目包含文件的组织管理 后缀为".pro"的 文件是项目的管理文件,文件名就是项目的名称,如Demo.p ...

  5. K8S日常运维中关于“ImagePullBackOff”报错的处理思路分析

    故障案例: 发现故障:kubectl get pod -n kube-system -owide|grep -v "Running"NAME READY STATUS RESTAR ...

  6. 性能测试工具JMeter 基础(二)—— 主界面介绍

    主界面介绍 JMeter的主界面主要分为菜单导航栏.工具栏.计划树标签栏.内容栏 菜单导航栏:全部的功能的都包含在菜单栏中 工具栏:相当于菜单栏常用功能的快捷按钮 计划树标签栏:显示测试用例(计划)相 ...

  7. HashSet的存储原理

    HashSet的底层用哈希散列表来存储对象(默认长度为16的数组),假如: Set set=new HashSet(); set.add(obj); 内部存储过程为:定义h=obj.hashCode, ...

  8. mybatis动态sql以及分页

    1.mybatis动态sql 2.模糊查询 3.查询返回结果集的处理 4.分页查询 5.特殊字符处理 1.mybatis动态sql If.trim.foreach If 标签判断某一字段是否为空 &l ...

  9. Vs code添加自定义snippet

    Vs code添加自定义snippet(代码段) 前言 ​ 代码段能够帮助输入重复代码模式,在智能感知下可以帮我们快速补全代码,节省时间方便之余更利于代码格式的统一规范化. 1. Vs code代码段 ...

  10. Python习题集(五)

    每天一习题,提升Python不是问题!!有更简洁的写法请评论告知我! https://www.cnblogs.com/poloyy/category/1676599.html 题目 打印99乘法表 解 ...