题目:https://loj.ac/problem/2736

如果每个询问都是 l = 1 , r = n ,那么每次输出序列的 n 个数与本次操作的数的最大值即可。可以用堆维护。

不同区间的询问,可以分块!

考虑如果 l = 1 , r = n ,怎么知道最后的序列每个位置是什么。

可以这样:把所有操作的数字都放进小根堆里,依次遍历每个位置,如果堆顶比该位置的值小,就把该位置的值换成堆顶的值,堆里删掉原堆顶,加入该位置原来的值。

分块的话,每个块开两个大根堆,一个 yq 维护原序列的数字,一个 q 维护新加入的数字,再维护住 a[ ] 表示上次更新之后每个位置的值。

对整块操作一个数 x ,可以知道 yq 和 q 两个堆总体的最大值会被删掉(如果这个最大值是 > x 的)。于是在最大值所在的堆里删掉最大值,把 x 放进 q 里。

最后想知道这块每个位置的值,就拿着 q 在各位置走一遍,一边换一番。所以之所以要开一个 yq ,是为了体现 “原来在自己后面的比自己小的值不能挪到自己位置上” 。

每个询问,如果是在不整的块上,就先把那个块按上面的步骤做一遍,那么 a[ ] 维护的就是真实值了;做完把 q 清空,然后暴力枚举位置把 a[ ] 更新,再把 yq 更新即可。

经过一个零散块或者整块之后,操作的 x 可能改变;把改变后的 x 当作输入给下一个块就行了。

复杂度是 \( n \sqrt{n} logn \) ,9 s 还是可以的。

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. #include<queue>
  5. #include<cmath>
  6. using namespace std;
  7. int rdn()
  8. {
  9. int ret=;bool fx=;char ch=getchar();
  10. while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
  11. while(ch>=''&&ch<='')ret=ret*+ch-'',ch=getchar();
  12. return fx?ret:-ret;
  13. }
  14. int Mx(int a,int b){return a>b?a:b;}
  15. const int N=4e5+,M=;
  16. int n,m,a[N],bs,bh[N],L[M],R[M];
  17. priority_queue<int> q[M],yq[M];
  18. priority_queue<int,vector<int>,greater<int> > tq[M];
  19. int bl(int l,int r,int x)
  20. {
  21. int k=bh[l];
  22. while(tq[k].size())tq[k].pop();
  23. while(q[k].size())tq[k].push(q[k].top()),q[k].pop();
  24. if(tq[k].size())//
  25. {
  26. for(int i=L[k];i<=R[k];i++)
  27. {
  28. int d=tq[k].top(); if(d>=a[i])continue;
  29. tq[k].pop(); tq[k].push(a[i]); a[i]=d;
  30. }
  31. }
  32. for(int i=l;i<=r;i++) if(x<a[i])swap(a[i],x);
  33. while(yq[k].size())yq[k].pop();
  34. for(int i=L[k];i<=R[k];i++)yq[k].push(a[i]);
  35. return x;
  36. }
  37. int solve(int l,int r,int x)
  38. {
  39. if(bh[l]==bh[r])return bl(l,r,x);
  40. x=bl(l,R[bh[l]],x); int k;
  41. for(k=bh[l]+;k<=m&&R[k]<=r;k++)//k<=m
  42. {
  43. if(yq[k].size()&&q[k].size())
  44. {
  45. int d0=q[k].top(), d1=yq[k].top();
  46. if(Mx(d0,d1)<=x)continue;
  47. if(d0>d1)
  48. {q[k].pop(); q[k].push(x); x=d0;}
  49. else
  50. {yq[k].pop(); q[k].push(x); x=d1;}//q.push
  51. }
  52. else if(yq[k].size())
  53. {
  54. int d=yq[k].top();
  55. if(d>x){yq[k].pop();q[k].push(x);x=d;}
  56. }
  57. else if(q[k].size())
  58. {
  59. int d=q[k].top();
  60. if(d>x){q[k].pop();q[k].push(x);x=d;}
  61. }
  62. }
  63. if(k<=m&&R[k-]<r)x=bl(L[k],r,x);//k<=m//R[k-1] not R[k]
  64. return x;
  65. }
  66. int main()
  67. {
  68. n=rdn(); int Q=rdn(); bs=sqrt(n);
  69. for(int i=;i<=n;i++)a[i]=rdn();
  70. L[]=; m=;
  71. for(int i=,j=;i<=n;i++)
  72. {
  73. j++; if(j>bs){R[m]=i-;m++;L[m]=i;j=;}
  74. bh[i]=m; yq[m].push(a[i]);
  75. }
  76. R[m]=n;
  77. int l,r,x;
  78. while(Q--)
  79. {
  80. l=rdn();r=rdn();x=rdn();
  81. if(l<=r)x=solve(l,r,x);
  82. else x=solve(l,n,x), x=solve(,r,x);
  83. printf("%d\n",x);
  84. }
  85. return ;
  86. }

LOJ 2736 「JOISC 2016 Day 3」回转寿司 ——堆+分块思路的更多相关文章

  1. 「JOISC 2016 Day 3」回转寿司

    https://loj.ac/problem/2736 题解 挺有意思的题. 考虑这种操作不好直接维护,还有时限比较长,所以考虑分块. 考虑一个操作对整个块的影响,无非就是可能把最大的拿走,再把新的元 ...

  2. Loj #2731 「JOISC 2016 Day 1」棋盘游戏

    Loj 2731 「JOISC 2016 Day 1」棋盘游戏 JOI 君有一个棋盘,棋盘上有 \(N\) 行 \(3\) 列 的格子.JOI 君有若干棋子,并想用它们来玩一个游戏.初始状态棋盘上至少 ...

  3. LOJ 2737 「JOISC 2016 Day 3」电报 ——思路+基环树DP

    题目:https://loj.ac/problem/2737 相连的关系形成若干环 / 内向基环树 .如果不是只有一个环的话,就得断开一些边使得图变成若干链.边的边权是以它为出边的点的点权. 基环树的 ...

  4. LOJ #2731. 「JOISC 2016 Day 1」棋盘游戏(dp)

    题意 JOI 君有一个棋盘,棋盘上有 \(N\) 行 \(3\) 列 的格子.JOI 君有若干棋子,并想用它们来玩一个游戏.初始状态棋盘上至少有一个棋子,也至少有一个空位. 游戏的目标是:在还没有放棋 ...

  5. [LOJ#2732] 「JOISC 2016 Day 2」雇佣计划

    参考博文 (不过个人感觉我讲的稍微更清楚一点) 题目就是让我们求图中满足数值大于等于B的连通块数量 然后我们可以尝试转换为求连通块两端所产生的“谷”的数量,显然一个连通块对谷可以贡献2的答案,最终答案 ...

  6. 「JOISC 2016 Day 1」棋盘游戏

    「JOISC 2016 Day 1」棋盘游戏 先判无解:第1,3行有连续的空格或四个角有空格. 然后可以发现有解的情况第1,3行可以在任意时间摆放. 对于某一列,若第2行放有棋子,那么显然可以把棋盘分 ...

  7. loj 2392「JOISC 2017 Day 1」烟花棒

    loj 答案显然满足二分性,先二分一个速度\(v\) 然后显然所有没有点火的都会往中间点火的人方向走,并且如果两个人相遇不会马上点火,要等到火快熄灭的时候才点火,所以这两个人之后应该在一起行动.另外有 ...

  8. loj2734「JOISC 2016 Day 2」女装大佬 || 洛谷P3615 如厕计划

    loj2734 洛谷P3615 http://218.5.5.242:9021/problem/185 不会做... 题解(来自ditoly): 这一步更详细的解释(来自kkksc03): 还是从后面 ...

  9. [LOJ #2833]「JOISC 2018 Day 1」帐篷

    题目大意:有一个$n\times m$的网格图,若一个人的同一行或同一列有人,他就必须面向那个人,若都无人,就可以任意一个方向.若一个人无法确定方向,则方案不合法,问不同的方案数.$n,m\leqsl ...

随机推荐

  1. 20165326 java第九周学习笔记

    第九周学习笔记 URL类 属于java.net包 最基本三部分:协议(对象所在的Java虚拟机支持).地址(能连接的有效IP地址或域名).资源(主机上的任何一个文件) 常用构造方法 public UR ...

  2. Unity3D使用OpenFileDialog后崩溃

    http://ask.unitymanual.com/question/24922 找了很久,原来是我的dll文件引错了,名字都一样,应该引用unity安装目录下的System.Window.Form

  3. 使用OpenBTS基站测试物联网模块安全性

    0×00 引子 近年来,随着云计算.物联网技术的快速发展,物联网的理念和相关技术产品已经广泛渗透到社会经济民生的各个领域,越来越多的穿戴设备.家用电器通过蓝牙.Wi-Fi.Li-Fi.z-wave.L ...

  4. mysql增删改查练习

    Mysql增删改查sql语句练习 关于数据库的一些操作: 进入mysql 命令行: mysql -uroot –p 查看所有数据库: show databases; 创建数据库: create dat ...

  5. Linux运维命令总结(-)

    Linux运维命令总结(-)  此次整理linux运维常用命令13个,常用linux运维命令大概有150个,约占百分之十,大牛见笑,本人菜鸟一枚不才整理如下,如有不正确之处,请多多指正. 1.创建目录 ...

  6. 2019-04-02-day024-内置方法

    昨日回顾 反射 用"字符串"类型的属性名/方法名来找到 属性的值或者方法的内存地址 所有可以反射的内容实际上都是变量 有内存地址 内存地址存的是"具体的值",直 ...

  7. ES6 声明变量的6种方法

    ES5 只有两种声明变量的方法:var命令和function命令. ES6除了添加let和const命令,后面章节还会提到,另外两种声明变量的方法:import命令和class命令.所以,ES6 一共 ...

  8. [LeetCode&Python] Problem 242. Valid Anagram

    Given two strings s and t , write a function to determine if t is an anagram of s. Example 1: Input: ...

  9. Gym.102006:Syrian Collegiate Programming Contest(寒假自训第11场)

    学习了“叙利亚”这个单词:比较温和的一场:几何的板子eps太小了,坑了几发. A .Hello SCPC 2018! 题意:给定一个排列,问它是否满足,前面4个是有序的,而且前面4个比后面的都小. 思 ...

  10. P1441 砝码称重(搜索+队列dp)

    题目链接:传送门 题目大意: 给你n个砝码ai,从中去掉m个后求最多的砝码可表示的重量. n≤20,m≤4,m<n,ai≤100. 思路: 用dfs搜掉m个砝码,然后用队列dp跑出答案,维护答案 ...