当前位置:   article > 正文

HDU6602线段树+思维_hdu6602详解

hdu6602详解

http://acm.hdu.edu.cn/showproblem.php?pid=6602

题意:给出一个1e5规模数列,数字范围也在1e5内,给出K,求最长子序列,使得序列中出现的任一数字都至少出现K次。

考虑枚举右端点,尺取法不好做,因为左端点没有简单的找法,,我们这样拆分问题:首先考虑每个数字的合法左端点的取法,易知对于数字a,若i出现不足K次,则左端点只能在最后一次a出现之后,即(最后一次a出现的位置,i];如果a已经出现了K次,则还可以在[1,往前数第K次的位置)取到。于是我们考虑到,可以沿着数列a[i]更新区间状态,对于每个a[i],根据a[i]是否已出现K次有两种更新左端点合理区间的操作。所以可以用线段树,使得对于每个数来说合理的左端点区间取值为1,不合理为0。最后query时,若某个点上值为c(数值上限),则说明该区间可取,因为每个数字在这个区间上都是合理的(要么不出现,要么已出现K次)。

 

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<vector>
  4. using namespace std;
  5. #define ls (rt<<1)
  6. #define rs (rt<<1|1)
  7. const int maxn=100010;
  8. int n,c,k;
  9. int a[maxn];
  10. vector<int> pos[maxn];
  11. struct Node{
  12. int dat,lazy;
  13. //dat的值为该段的合法点数量,需为c
  14. }tr[maxn<<2];
  15. int now[maxn];//表示某个数值的当前坐标
  16. void pushup(int rt){
  17. tr[rt].dat=max(tr[ls].dat,tr[rs].dat);
  18. //有一个合法则该段合法
  19. }
  20. void pushdown(int rt){
  21. if(tr[rt].lazy){
  22. tr[ls].dat+=tr[rt].lazy;
  23. tr[rs].dat+=tr[rt].lazy;
  24. tr[ls].lazy+=tr[rt].lazy;
  25. tr[rs].lazy+=tr[rt].lazy;
  26. tr[rt].lazy=0;
  27. }
  28. }
  29. void build(int rt,int l,int r){
  30. tr[rt].lazy=0;
  31. if(l==r){
  32. tr[rt].dat=0;
  33. return;
  34. }
  35. int mid=(l+r)>>1;
  36. build(ls,l,mid);
  37. build(rs,mid+1,r);
  38. pushup(rt);
  39. }
  40. void update(int rt,int l,int r,int L,int R,int val){
  41. if(L>R)
  42. return;
  43. if(L<=l&&r<=R){
  44. tr[rt].dat+=val;
  45. tr[rt].lazy+=val;
  46. return;
  47. }
  48. pushdown(rt); //要对该区间继续向下更新了,先把lazy标记处理了
  49. int mid=(l+r)>>1;
  50. if(L<=mid){
  51. update(ls,l,mid,L,R,val);
  52. }
  53. if(R>mid){
  54. update(rs,mid+1,r,L,R,val);
  55. }
  56. pushup(rt);
  57. }
  58. int query(int rt,int l,int r){
  59. if(l==r){
  60. return l;
  61. }
  62. int res=-1;
  63. int mid=(l+r)>>1;
  64. pushdown(rt);
  65. if(tr[ls].dat==c)
  66. res=query(ls,l,mid);
  67. else if(tr[rs].dat==c)
  68. res=query(rs,mid+1,r);
  69. return res;
  70. }
  71. int main(){
  72. while(~scanf("%d%d%d",&n,&c,&k)){
  73. for(int i=1;i<=c;i++){
  74. pos[i].clear();
  75. pos[i].push_back(0);
  76. }
  77. for(int i=1;i<=n;i++){
  78. scanf("%d",a+i);
  79. pos[a[i]].push_back(i);
  80. }
  81. build(1,1,n);
  82. for(int i=1;i<=c;i++){
  83. pos[i].push_back(n+1);
  84. update(1,1,n,pos[i][0]+1,pos[i][1]-1,1);
  85. now[i]=0;
  86. }
  87. int ans=0;
  88. for(int i=1;i<=n;i++){
  89. int res=0;
  90. int t=a[i];
  91. update(1,1,n,pos[t][now[t]]+1,pos[t][now[t]+1]-1,-1);
  92. // if(now[t]>=k)
  93. // update(1,1,n,1,pos[t][now[t]-k+1],-1);
  94. now[t]++; //更新当前值的个数
  95. update(1,1,n,pos[t][now[t]]+1,pos[t][now[t]+1]-1,1);
  96. if(now[t]>=k)
  97. update(1,1,n,pos[t][now[t]-k]+1,pos[t][now[t]-k+1],1);
  98. res=query(1,1,n);
  99. if(res!=-1)
  100. ans=max(ans,i-res+1);
  101. }
  102. printf("%d\n",ans);
  103. }
  104. return 0;
  105. }

 

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

闽ICP备14008679号