当前位置:   article > 正文

回转寿司

javascript回转寿司

Description

o_20180416193127_56582.png
o_20180416193134_39092.png
o_20180416193141_54339.png
o_20180416193147_71297.png


Solution
  • 12%

  暴力

  

  • 40%

  在暴力的基础上,我们特殊处理一下s=1t=n的情况,因为每次都是从这个区间过,所以我们只需要维护一下这个区间的最大值,每次跟寿司比较,如果寿司更小就直接交换就好了(其他的值并不需要维护,因为每次都是这个区间所以顺序并不重要)

  具体实现的话优先队列就好了
  

  • 100%

  从上面的子任务我们得到启发,考虑分块,假设块的大小为B,对于每一个块我们都维护一个大根堆(啊但实现的时候不想写用优先队列也没什么问题),堆中的元素为块内的所有元素

  如果说有一个寿司的移动完全跨过了一个块,那么我们就把堆顶的元素跟这个寿司比较一下,如果寿司更小就交换,那么一次操作是logn的,对于跨过不是完整块的部分,我们暴力比较更新

  但是有个问题,子任务中是永远都只会跨过一个区间,也就是说不存在块内的修改,所以不需要维护具体某个位置是什么值,只要看整个块有哪些值就好了,但是我们现在需要处理块内的修改,所以要想办法将位置这个信息还原出来

  我们考虑整块修改的时候,给每个块打上标记

  考虑这样一个过程,对于一个块,每次的整块修改我们都将用来更新的值存到一个tag数组里面,然后最后再一次性下传,更新每个位置的值

  考虑一下更换寿司的规则,会发现每个寿司是一遇到比自己大的就交换,手动模拟一下,会发现其实就是从左到右更新块中每个位置的值,每次从tag数组中找到最小的那个,比较一下,如果可以更新就交换(把原来tag中的最小值删掉,把这个位置原来的值丢进tag数组),然后再比较下一个

  由于每次需要用的是最小值,所以我们可以考虑用对于每一个块用一个小根堆来维护所有的tag,每次需要块内修改的时候,先将tag下传,然后再进行块内的修改操作

  这样,一次标记下传的复杂度就是B log q了(B是块大小,q是新寿司的数量)

  总的时间复杂度为O(q(B log q+ nBlog n)),假定nq同阶,并且将B设为n,那么总的时间复杂度为O(q n log n)

​  

  (然后我们算一下发现这很爆炸的样子。。。但是。。抱歉它就是能过qwq。。)

  分块真的可以为所欲为

  题外话:然而好像块大小开根号并不是最快的。。。具体开多少跑的比较快就没有大力调参了qwq

  

  代码大概长这个样子

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<vector>
  5. #include<queue>
  6. #include<cmath>
  7. #define Pq priority_queue<int>
  8. using namespace std;
  9. const int MAXN=4*(1e5)+10;
  10. Pq people[MAXN],tmpPq;
  11. vector<int> tag[MAXN];
  12. int a[MAXN];
  13. int n,m,sq,all;
  14. int Id(int x){return (x-1)/sq+1;}
  15. int St(int x){return (x-1)*sq+1;}
  16. int Ed(int x){return min(n,St(x)+sq-1);}
  17. int solve(int l,int r,int w);
  18. void update(int x);
  19. void solve_small(int l,int r,int &w);
  20. void solve_big(int x,int &w);
  21. int main(){
  22. #ifndef ONLINE_JUDGE
  23. freopen("a.in","r",stdin);
  24. #endif
  25. int l,r,w;
  26. scanf("%d%d",&n,&m);
  27. for (int i=1;i<=n;++i) scanf("%d",a+i);
  28. sq=sqrt(n); all=(n-1)/sq;
  29. for (int i=1;i<=Id(n);++i) tag[i].clear();
  30. for (int i=1;i<=n;++i)
  31. people[Id(i)].push(a[i]);
  32. for (int i=1;i<=m;++i){
  33. scanf("%d%d%d",&l,&r,&w);
  34. if (l<=r)
  35. printf("%d\n",solve(l,r,w));
  36. else
  37. printf("%d\n",solve(1,r,solve(l,n,w)));
  38. }
  39. }
  40. int solve(int l,int r,int w){
  41. int numl,numr;
  42. if (Id(l)==Id(r))
  43. solve_small(l,r,w);
  44. else{
  45. numl=Id(l); numr=Id(r);
  46. if (l!=St(numl))
  47. solve_small(l,Ed(numl),w);
  48. else
  49. solve_big(numl,w);
  50. for (int i=numl+1;i<numr;++i)
  51. solve_big(i,w);
  52. if (r!=Ed(numr))
  53. solve_small(St(numr),r,w);
  54. else
  55. solve_big(numr,w);
  56. }
  57. return w;
  58. }
  59. void update(int x){
  60. if (tag[x].empty()) return;
  61. priority_queue<int,vector<int>,greater<int> > tmpPq(tag[x].begin(),tag[x].end());
  62. for (int i=St(x);i<=Ed(x);++i){
  63. if (a[i]>tmpPq.top()){
  64. tmpPq.push(a[i]);
  65. a[i]=tmpPq.top();
  66. tmpPq.pop();
  67. }
  68. }
  69. people[x]=Pq(a+St(x)+1,a+Ed(x)+1);//priority_queue可以这么赋值的嗯qwq
  70. tag[x].clear();
  71. }
  72. void solve_small(int l,int r,int &w){
  73. int x=Id(l);
  74. update(x);
  75. for (int i=l;i<=r;++i)
  76. if (w<a[i])
  77. swap(a[i],w);
  78. people[x]=Pq(a+St(x),a+Ed(x)+1);
  79. }
  80. void solve_big(int x,int &w){
  81. if (w>=people[x].top()) return;
  82. tag[x].push_back(w);
  83. people[x].push(w);
  84. w=people[x].top();
  85. people[x].pop();
  86. }

转载于:https://www.cnblogs.com/yoyoball/p/8907615.html

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