[关闭]
@xiaoziyao 2021-07-29T22:08:01.000000Z 字数 1277 阅读 923

CF1404C Fixed Point Removal解题报告

解题报告


CF1404C Fixed Point Removal解题报告:

更好的阅读体验

题意

给定长为 的序列 ,一次操作可以删除一个满足 的位置 ,同时之后的数向前移动一位。
次询问,每次给定 ,求不能删去前 个元素与后 个元素的情况下最多能删除多少元素。(

分析

套路题。

观察数据范围可知算法复杂度差不多是单 ,根据套路,我们将询问挂在右端点上,并从左往右扫,用数据结构维护左端点为 时的答案。

具体地,我们记 为可以删除的区间左端点为 时,有多少个点无法删除,可以发现加入一个点后我们只需要计算其对一段后缀的贡献。

扫描到 时,若 ,不难发现其一定无法删除,于是直接全局加一。否则,我们二分一个位置使得其前面已经有 个无法删除的位置,将这个位置对应的后缀与 对应的后缀取并并直接更新。

这种操作用树状数组可以轻松维护,二分的时候在树状数组上二分就可以了,时间复杂度

代码

  1. #include<stdio.h>
  2. #include<vector>
  3. #define lowbit(x) x&-x
  4. using namespace std;
  5. const int maxn=300005;
  6. int n,m;
  7. int a[maxn],ans[maxn],t[maxn];
  8. vector< pair<int,int> >v[maxn];
  9. void update(int x,int v){
  10. for(int i=x;i<=n;i+=lowbit(i))
  11. t[i]+=v;
  12. }
  13. int query(int x){
  14. int res=0;
  15. for(int i=x;i;i-=lowbit(i))
  16. res+=t[i];
  17. return res;
  18. }
  19. int getkth(int k){
  20. int res=0;
  21. for(int i=18;i>=0;i--)
  22. if(res+(1<<i)<=n&&k>t[res+(1<<i)])
  23. k-=t[res+(1<<i)],res+=(1<<i);
  24. return res+1;
  25. }
  26. int main(){
  27. scanf("%d%d",&n,&m);
  28. for(int i=1;i<=n;i++)
  29. scanf("%d",&a[i]);
  30. for(int i=1;i<=m;i++){
  31. int x,y;
  32. scanf("%d%d",&x,&y);
  33. x++,y=n-y;
  34. if(x<=y)
  35. v[y].push_back(make_pair(x,i));
  36. }
  37. for(int i=1,tot=0;i<=n;i++){
  38. if(i-a[i]>=0){
  39. tot++;
  40. int pos=getkth(a[i]);
  41. if(pos<=i)
  42. update(pos,1);
  43. else update(i+1,1);
  44. }
  45. for(int j=0;j<v[i].size();j++)
  46. ans[v[i][j].second]=tot-query(v[i][j].first);
  47. }
  48. for(int i=1;i<=m;i++)
  49. printf("%d\n",ans[i]);
  50. return 0;
  51. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注