当前位置:   article > 正文

回转寿司——有趣的分块_c++寿司盘子颜色 题目

c++寿司盘子颜色 题目

样例1输入: 
6 7
8 6 7 4 5 9
2 4 5
4 1 4
6 2 7
1 5 2
3 4 8
4 3 1
3 1 3
样例1输出:
7
9
8
7
8
6

样例1每次提供完新寿司后,顾客拥有的寿司价格依次为:
1.8 5 6 4 5 9
2.8 5 6 4 4 5
3.7 5 6 4 4 5
4.2 5 6 4 4 5
5.2 5 6 4 4 5
6.2 5 5 1 4 4

7.2 5 3 1 4 4 

 

样例2输入:
4 2
5 2 4 7
1 4 3
1 4 1
样例2输出:
7
5
 
样例3输入:
10 10
19 5 8 17 14 3 9 10 7 6
1 8 4
7 3 2
5 9 10
4 8 3
10 3 6
8 7 4
6 6 3
2 9 12
6 3 7
9 6 3
样例3输出:
19
10
14
17
8
10
3
12
7

9

n<=40w,q<=2.5w,时限4s

很有意思的一道题。区间问题除了线段树等数据结构之外,一般用分块和莫队解决,而这道题有在线操作的意味,因此后者pass~

考虑分块,显然,每一次进入区间后,寿司的数量是不会变的,而且,寿司滚出这个区间之后显然是这段区间+新寿司中的最大值,因此我们可以用大根堆来维护每一个块的最大值,那么每一个块滚出寿司最大值之后,最后滚出的寿司必然也是最大值。

整块搞好了,那么如何处理散块呢?只有散块我们需要具体的值,所以我们可以像线段树一样向块打标记,等到成为散块处理的时候再更新。因为是按顺序滚的,而且每个人都会选择最小值,所以我们用小根堆维护。

至此,小根堆+大根堆+分块完美解决,时间复杂度q√nlogn

……值得注意的是,直接用stl会炸,因此我们需要一些优化~详见代码

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int N = 4e5+10,M = 25010,Maxsiz = 637;
  4. #define Inc(i,L,r) for(register int i=(L);i<=(r);++i)
  5. int n,Q,a[N];
  6. int siz,bl[N];
  7. vector<int>vec[Maxsiz];//记录修改操作
  8. priority_queue<int>Max[Maxsiz];//大根堆
  9. inline void construct(int idx){
  10. Max[idx]=priority_queue<int>(a+(idx-1)*siz+1,a+min(idx*siz,n)+1);//重构操作就是重新把一段区间塞进去,要比单纯的push()pop()快?
  11. }
  12. inline void init(){
  13. scanf("%d%d",&n,&Q);
  14. Inc(i,1,n)scanf("%d",&a[i]);
  15. siz=sqrt(n);
  16. Inc(i,1,n)bl[i]=(i-1)/siz+1;
  17. Inc(i,1,n)Max[bl[i]].push(a[i]);//初始化块的最大值
  18. }
  19. inline void update(int idx){//我们注意到,每次只会流动一个,是不是和线段树的标记下传很像?
  20. if(vec[idx].empty())return ;
  21. priority_queue<int,vector<int>,greater<int> >Min(vec[idx].begin(),vec[idx].end());
  22. Inc(i,(idx-1)*siz+1,min(idx*siz,n)){
  23. int HeapTop=Min.top();
  24. if(a[i]>HeapTop)Min.pop(),Min.push(a[i]),a[i]=HeapTop;
  25. }
  26. construct(idx);
  27. vec[idx].clear();
  28. }
  29. inline int Query(int L,int r,int k){
  30. int ret=k;
  31. if(bl[r]-bl[L]<=1){
  32. update(bl[L]);//只有处理散块的时候,我们才更新
  33. if(bl[r]^bl[L])update(bl[r]);
  34. Inc(i,L,r)if(a[i]>ret)swap(a[i],ret);
  35. construct(bl[L]);
  36. if(bl[r]^bl[L])construct(bl[r]);
  37. }else {
  38. update(bl[L]);
  39. Inc(i,L,bl[L]*siz)if(a[i]>ret)swap(a[i],ret);
  40. construct(bl[L]);
  41. Inc(i,bl[L]+1,bl[r]-1){
  42. vec[i].push_back(ret);//我们假装把寿司扔进这个块里让它滚一遍
  43. int tmp=ret;
  44. Max[i].push(tmp);
  45. ret=Max[i].top();//最大的会滚出来
  46. Max[i].pop();
  47. }
  48. update(bl[r]);
  49. Inc(i,(bl[r]-1)*siz+1,r)if(a[i]>ret)swap(a[i],ret);
  50. construct(bl[r]);
  51. }return ret;
  52. }
  53. inline void solv(){
  54. while(Q--){
  55. int L,r,k;scanf("%d%d%d",&L,&r,&k);
  56. if(L<=r)cout<<Query(L,r,k)<<"\n";
  57. else cout<<Query(1,r,Query(L,n,k))<<'\n';
  58. }
  59. }
  60. int main(){
  61. init();
  62. solv();
  63. return 0;
  64. }

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/622330
推荐阅读
相关标签
  

闽ICP备14008679号