[关闭]
@IOU 2018-02-08T06:20:36.000000Z 字数 1505 阅读 913

P1972 [SDOI2009]HH的项链

莫队 信息 洛谷


看到题解里提到一种神奇的算法——莫队,据说可以解决一切区间问题。。。
核心思想就是利用当前求的区间的值推知接下来要求的区间的值,因为已知区间f[l][r],我们可以很快地求得区间或者,因而可以逐步地推出下一个区间要求的值。
但是如果单纯只是这样算的话,复杂度有,这也没有体现莫队”优雅的暴力“的美称。
于是就有了莫队算法的精华——分块,我们知道,在推出下一个区间的过程中,尽量地使下一个区间和当前的区间的交集最大,就可以让推的过程尽量地短,于是按照一定地顺序求解,也就是我们通常讲的离线算法,在此就显得尤为重要了。
单纯的排序,即以左端点为第一关键字,右端点为第二关键字,固然可以减少左指针的移动,但右边的指针则会跑来跑去。为了尽量让右指针来回的次数少,可以相对地牺牲一点左边。把所有的区间按左端点分块,相同一块的区间再按右端点排序,这样一来,单纯就一个块而言,左指针只会在自己那一块里移动,右指针只会从头到尾扫一遍,这样就节省了很多时间。
分块大多分为块,每块个区间,至于为什么这样分,我也不知道。。。
算一算时间复杂度,就是



就得到一个的算法了
这道题就是个裸的莫队吧
下面是代码

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cmath>
  4. #include<cstring>
  5. #include<algorithm>
  6. using namespace std;
  7. int judge[10000001];
  8. int seq[50001],p[200001];
  9. struct node
  10. {
  11. int l,r,t,id,ans;
  12. }a[200001];
  13. bool my_comp(const node x,const node y)
  14. {
  15. if(x.t==y.t)return x.r<y.r;
  16. return x.l<y.l;
  17. }
  18. int main()
  19. {
  20. int n,m;
  21. cin>>n;
  22. int len=sqrt(n);
  23. for(int i=1;i<=n;i++)
  24. scanf("%d",&seq[i]);
  25. cin>>m;
  26. for(int i=1;i<=m;i++)
  27. {
  28. scanf("%d%d",&a[i].l,&a[i].r);
  29. a[i].t=a[i].l/len;
  30. a[i].id=i;
  31. }
  32. sort(a+1,a+1+m,my_comp);
  33. int left=0,right=0,ans=0;
  34. for(int i=1;i<=m;i++)
  35. {
  36. while(left<a[i].l)
  37. {
  38. judge[seq[left]]--;
  39. if(judge[seq[left++]]==0)
  40. ans--;
  41. }
  42. while(left>a[i].l)
  43. {
  44. if(!judge[seq[left-1]])
  45. ans++;
  46. judge[seq[--left]]++;
  47. }
  48. while(right<a[i].r)
  49. {
  50. if(!judge[seq[right+1]])
  51. ans++;
  52. judge[seq[++right]]++;
  53. }
  54. while(right>a[i].r)
  55. {
  56. judge[seq[right]]--;
  57. if(!judge[seq[right--]])
  58. ans--;
  59. }
  60. p[a[i].id]=ans;
  61. }
  62. for(int i=1;i<=m;i++)
  63. printf("%d\n",p[i]);
  64. return 0;
  65. }

参考: modui

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注