[关闭]
@iamtts 2017-05-14T15:38:01.000000Z 字数 3488 阅读 990

st表与线段树

A - Hotel

题意:一开始有n个连续空房间编号从1到n,现在有两种操作:

1.入住,给出人数k,要求连续k间空房,若无法满足则输出0,满足则输出满足条件且最左边的房间号
2.清空,从房间a到b全部清空

解题思路:用到线段树的区间合并,线段树节点保存管理的区间(l,r),区间内空房最大连续长度(sum),从最左/右边开始最大连续空房间长度(lsum,rsum),和懒惰标记(flag)

AC代码:

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <algorithm>
  4. #include <iostream>
  5. using namespace std;
  6. const int N = 100000 + 5;
  7. struct node
  8. {
  9. int lsum,rsum,sum,l,r,flag;
  10. } tree[N*4];
  11. inline int MAX(int a,int b,int c)
  12. {
  13. return max(a,max(b,c));
  14. }
  15. void push_up(int now)
  16. {
  17. tree[now].lsum=tree[now<<1].lsum;
  18. tree[now].rsum=tree[now<<1|1].rsum;
  19. if (tree[now].lsum==tree[now<<1].r-tree[now<<1].l+1) tree[now].lsum+=tree[now<<1|1].lsum;
  20. if (tree[now].rsum==tree[now<<1|1].r-tree[now<<1|1].l+1) tree[now].rsum+=tree[now<<1].rsum;
  21. tree[now].sum=MAX(tree[now<<1].sum,tree[now<<1|1].sum,tree[now<<1].rsum+tree[now<<1|1].lsum);
  22. }
  23. void push_down(int now)
  24. {
  25. if (tree[now].flag!=-1)
  26. {
  27. tree[now<<1].flag=tree[now<<1|1].flag=tree[now].flag;
  28. if (tree[now].flag==1)
  29. {
  30. tree[now<<1].sum=tree[now<<1].lsum=tree[now<<1].rsum=0;
  31. tree[now<<1|1].sum=tree[now<<1|1].lsum=tree[now<<1|1].rsum=0;
  32. }
  33. else
  34. {
  35. tree[now<<1].sum=tree[now<<1].lsum=tree[now<<1].rsum=tree[now<<1].r-tree[now<<1].l+1;
  36. tree[now<<1|1].sum=tree[now<<1|1].lsum=tree[now<<1|1].rsum=tree[now<<1|1].r-tree[now<<1|1].l+1;
  37. }
  38. tree[now].flag=-1;
  39. }
  40. }
  41. void build_tree(int l,int r,int now)
  42. {
  43. tree[now].l=l;
  44. tree[now].r=r;
  45. tree[now].flag=-1;
  46. tree[now].lsum=tree[now].rsum=tree[now].sum=r-l+1;
  47. if (l==r) return;
  48. int mid=(r+l)/2;
  49. build_tree(l,mid,now<<1);
  50. build_tree(mid+1,r,now<<1|1);
  51. }
  52. int query_tree(int l,int r,int now,int x)
  53. {
  54. if (r==l) return l;
  55. int mid=(l+r)/2;
  56. push_down(now);
  57. if (tree[now<<1].sum>=x) return query_tree(l,mid,now<<1,x);
  58. else if (tree[now<<1].rsum+tree[now<<1|1].lsum>=x) return mid-tree[now<<1].rsum+1;
  59. else return query_tree(mid+1,r,now<<1|1,x);
  60. }
  61. void update(int l,int r,int now,int x)
  62. {
  63. if (tree[now].l==l &&tree[now].r==r)
  64. {
  65. tree[now].flag=x;
  66. if (x)
  67. {
  68. tree[now].sum=tree[now].lsum=tree[now].rsum=0;
  69. }
  70. else
  71. {
  72. tree[now].sum=tree[now].lsum=tree[now].rsum=r-l+1;
  73. }
  74. return;
  75. }
  76. push_down(now);
  77. int mid=(tree[now].r+tree[now].l)/2;
  78. if (mid>=r) update(l,r,now<<1,x);
  79. else if (mid+1<=l) update(l,r,now<<1|1,x);
  80. else
  81. {
  82. update(l,mid,now<<1,x);
  83. update(mid+1,r,now<<1|1,x);
  84. }
  85. push_up(now);
  86. }
  87. int main()
  88. {
  89. int n,m;
  90. while(~scanf("%d%d",&n,&m))
  91. {
  92. build_tree(1,n,1);
  93. for (int i=1; i<=m; i++)
  94. {
  95. int judge;
  96. scanf("%d",&judge);
  97. if (judge==1)
  98. {
  99. int num;
  100. scanf("%d",&num);
  101. if (tree[1].sum<num) cout<<0<<endl;
  102. else
  103. {
  104. int x=query_tree(1,n,1,num);
  105. printf("%d\n",x);
  106. update(x,x+num-1,1,1);
  107. }
  108. }
  109. else
  110. {
  111. int x,y;
  112. scanf("%d%d",&x,&y);
  113. update(x,x+y-1,1,0);
  114. }
  115. }
  116. }
  117. return 0;
  118. }

C - Assignment

题意:给出n个人的能力值,可以从他们中选人组成小组,要求每组里面任意两者的能力值之差小于k,问能分出多少不同的组

解题思路:用st表储存区间的最大值最小值,然后对每个i(from 1 to n)二分出右端点,判断条件就是区间最大值与最小值之差小于k

AC代码:

  1. #include<algorithm>
  2. #include<iostream>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cstdio>
  6. #include<cmath>
  7. #include<queue>
  8. using namespace std;
  9. #define N 100005
  10. int stmax[N][21],stmin[N][21];
  11. int a[N];
  12. int t,q,n,k;
  13. int x,y;
  14. void init()
  15. {
  16. for (int i=1;i<=n;i++)
  17. {
  18. stmax[i][0]=stmin[i][0]=a[i];
  19. }
  20. for (int j=1;(1<<j) <= n;j++)
  21. for (int i=1;i+(1<<j)-1<=n;i++)
  22. {
  23. stmax[i][j]=max(stmax[i][j-1],stmax[i+(1<<(j-1))][j-1]);
  24. stmin[i][j]=min(stmin[i][j-1],stmin[i+(1<<(j-1))][j-1]);
  25. }
  26. }
  27. bool ok(int L,int R)
  28. {
  29. int kk= log2(R - L + 1.0);
  30. int Max=max(stmax[L][kk],stmax[R-(1<<kk)+1][kk]);
  31. int Min=min(stmin[L][kk],stmin[R-(1<<kk)+1][kk]);
  32. //printf("%d~%d:%d\n",L,R,Max-Min);
  33. if (Max-Min<k) return true;
  34. return false;
  35. }
  36. int main()
  37. {
  38. scanf("%d",&t);
  39. while (t--)
  40. {
  41. long long cnt=0;
  42. scanf("%d%d",&n,&k);
  43. for (int i=1;i<=n;i++)
  44. scanf("%d",&a[i]);
  45. init();
  46. for (int i=1;i<=n;i++)
  47. {
  48. long long ub=n,lb=i,mid;
  49. while (ub-1>lb)
  50. {
  51. mid=(ub+lb)/2;
  52. if (ok(i,mid)) lb=mid;
  53. else ub=mid;
  54. }
  55. if (ok(i,ub)) cnt+=ub-i+1;
  56. else cnt+=lb-i+1;
  57. //printf("%d\n",mid-i+1);
  58. }
  59. printf("%lld\n",cnt);
  60. }
  61. return 0;
  62. }

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