[关闭]
@morehigh 2017-05-20T13:31:52.000000Z 字数 4145 阅读 1040

CQUPT 线段树+st专题 2017/5/8

线段数


A - Hotel POJ - 3667

  1. 旅馆里面有N(1 N 50,000)个房间,有M(1 M < 50,000)个操作,包含两类
  2. 1操作 需要占用连续的D个房间
  3. 2操作 从第X个房间到第X+D-1个房间被清空
  4. 进行1操作的时候,需要占用D个房间,需要查询输出r,表示从rr+D的房间是空出来的
  1. 线段数连续区间合并问题,lsum表示从左边端点开始连续的空房间的个数,rsum表示从最右边端点开始向左连续的空房间的个数,msum表示此区间最大连续区间,如果最大的连续区间小于要占用的区间D,则表示不满足条件输出‘0’。col表示lazy数组,如果col为-1表示不存在向下传递数据。pushdown表示向下传递标记,pushup表示向上传递最大父亲区间的最大连续区间。
  1. #include <iostream>
  2. #include <cstring>
  3. #include <cstdio>
  4. #include <algorithm>
  5. using namespace std;
  6. const int maxn=50005;
  7. int lsum[maxn*4], rsum[maxn*4], msum[maxn*4];
  8. int col[maxn*4];
  9. void push_down(int rt,int m)
  10. {
  11. if(col[rt]!=-1)
  12. {
  13. col[rt<<1]=col[rt<<1|1]=col[rt];
  14. msum[rt<<1]=lsum[rt<<1]=rsum[rt<<1]=col[rt]?0:m-(m>>1);
  15. msum[rt<<1|1]=lsum[rt<<1|1]=rsum[rt<<1|1]=col[rt]?0:(m>>1);
  16. col[rt]=-1;
  17. }
  18. }
  19. void push_up(int rt, int m) {
  20. lsum[rt]=lsum[rt<<1];
  21. rsum[rt]=rsum[rt<<1|1];
  22. if(lsum[rt]==m-(m>>1)) lsum[rt]+=lsum[rt<<1|1];
  23. if(rsum[rt] == (m>>1)) rsum[rt]+=rsum[rt<<1];
  24. msum[rt]=max(lsum[rt<<1|1]+rsum[rt<<1], max(msum[rt<<1], msum[rt<<1|1]));
  25. }
  26. void build(int l,int r,int rt)
  27. {
  28. msum[rt]=lsum[rt]=rsum[rt]=r-l+1;
  29. col[rt]=-1;
  30. if(l==r) return ;
  31. int mid=(l+r)>>1;
  32. build(l,mid,rt<<1);
  33. build(mid+1,r,rt<<1|1);
  34. }
  35. void update(int L,int R,int c,int rt,int l,int r)
  36. {
  37. if(L<=l&&R>=r){
  38. msum[rt]=lsum[rt]=rsum[rt]=c?0:r-l+1;
  39. col[rt]=c;
  40. return ;
  41. }
  42. push_down(rt,r-l+1);
  43. int mid=(l+r)>>1;
  44. if(L<=mid) update(L,R,c,rt<<1,l,mid);
  45. if(R>mid) update(L,R,c,rt<<1|1,mid+1,r);
  46. push_up(rt,r-l+1);
  47. }
  48. int query(int wid, int rt, int l, int r) {
  49. if(l == r) return l;
  50. push_down(rt, r - l + 1);
  51. int mid = (l + r) >> 1;
  52. if(msum[rt << 1] >= wid) return query(wid, rt<<1,l,mid);
  53. else if(rsum[rt << 1] + lsum[rt << 1|1] >= wid) return mid - rsum[rt << 1] + 1;
  54. return query(wid,rt<<1|1,mid+1,r);
  55. }
  56. int main()
  57. {
  58. int n,m;
  59. scanf("%d%d",&n,&m);
  60. build(1,n,1);
  61. while(m--)
  62. {
  63. int x,a,b;
  64. scanf("%d",&x);
  65. if(x==1)
  66. {
  67. scanf("%d",&a);
  68. if(msum[1]<a) printf("0\n");
  69. else{
  70. int l=query(a,1,1,n);
  71. printf("%d\n",l);
  72. update(l,l+a-1,1,1,1,n);
  73. }
  74. }else{
  75. scanf("%d%d",&a,&b);
  76. update(a,a+b-1,0,1,1,n);
  77. }
  78. }
  79. return 0;
  80. }

B - A Corrupt Mayor's Performance Art HDU - 5023

  1. 输入两个数据 N M (0 < N <= 1,000,000; 0<M<=100,000),表示在长度为N的墙壁上进行M个操作,涂颜色,一共有30种颜色,
  2. 1) P a b c ab区间涂上颜色c
  3. 2) Q a b 查询ab区间一共有几种颜色( 0 < a<=b <= N).
  1. 用到二进制存储压缩记录每个线段数区间所包含的颜色,初始颜色为2pushdown表示将更新得到的颜色向下传递,更新时将需要更新的颜色存储到add数组中,减少时间复杂度,pushup将子区间更改的颜色传递给父亲节点,其中用到了位运算。
  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int N=1100056;
  4. char s[10];
  5. long long sum[N*4],add[N*4];
  6. void pushdown(int rt)
  7. {
  8. if(add[rt])
  9. {
  10. add[rt<<1]=add[rt<<1|1]=add[rt];
  11. sum[rt<<1]=add[rt];
  12. sum[rt<<1|1]=add[rt];
  13. add[rt]=0;
  14. }
  15. }
  16. void pushup(int rt)
  17. {
  18. sum[rt]=sum[rt<<1]|sum[rt<<1|1];
  19. }
  20. void build(int rt,int l,int r)
  21. {
  22. add[rt]=0;
  23. if(l==r)
  24. {
  25. sum[rt]=2;
  26. return ;
  27. }
  28. int mid=(l+r)>>1;
  29. build(rt<<1,l,mid);
  30. build(rt<<1|1,mid+1,r);
  31. pushup(rt);
  32. }
  33. void update(int L,int R,int c,int rt,int l,int r)
  34. {
  35. if(L<=l&&R>=r)
  36. {
  37. add[rt]=1<<(c-1);
  38. sum[rt]=1<<(c-1);
  39. return ;
  40. }
  41. pushdown(rt);
  42. int mid=(l+r)>>1;
  43. if(L<=mid)
  44. update(L,R,c,rt<<1,l,mid);
  45. if(R>mid)
  46. update(L,R,c,rt<<1|1,mid+1,r);
  47. pushup(rt);
  48. }
  49. long long query(int a,int b,int rt,int l,int r)
  50. {
  51. if(a<=l&&b>=r)
  52. {
  53. return sum[rt];
  54. }
  55. pushdown(rt);
  56. long long ret=0;
  57. int mid=(l+r)>>1;
  58. if(a<=mid) ret|=query(a,b,rt<<1,l,mid);
  59. if(b>mid) ret|=query(a,b,rt<<1|1,mid+1,r);
  60. return ret;
  61. }
  62. int main()
  63. {
  64. int n,m;
  65. int a,b,c;
  66. while(~scanf("%d%d",&n,&m))
  67. {
  68. if(n==0&&m==0)
  69. break;
  70. build(1,1,n);
  71. while(m--)
  72. {
  73. scanf("%s",s);
  74. if(s[0]=='P')
  75. {
  76. scanf("%d%d%d",&a,&b,&c);
  77. update(a,b,c,1,1,n);
  78. }else{
  79. scanf("%d%d",&a,&b);
  80. long long t=query(a,b,1,1,n);
  81. int flag=0;
  82. for(int i=1;i<=30;i++)
  83. {
  84. if(t>>(i-1)&1 && flag==0)
  85. {
  86. printf("%d",i);
  87. flag = 1;
  88. }
  89. else if(t>>(i-1)&1)
  90. printf(" %d",i);
  91. }
  92. printf("\n");
  93. }
  94. }
  95. }
  96. return 0;
  97. }

C - Assignment HDU - 5289

  1. 一个公司有n个员工,每个员工有一个大小为x能力,老板想把能力差大小不超过k的员工分到一组,求出老板能把员工分成多少组。(1<=n<=100000, 0<k<=10^9)
  1. ST做一个预处理,处理得到的数组mx[i][j]表示区间ii^j中最大的数字。mn[i][j]表示区间ii^j中最小的数字。然后要用到二分查找,判断ij区间最大值与最小值差小于k。计算满足条件的区间数。
  1. #include <bits/stdc++.h>
  2. #define N 100005
  3. using namespace std;
  4. int a[N];
  5. int mx[N][21], mn[N][21];
  6. int n, k;
  7. void ST()
  8. {
  9. for(int j=1;(1<<j)<=n;j++)
  10. {
  11. for(int i=1;i+(1<<j)-1<=n;i++)
  12. {
  13. int p = 1<<(j - 1);
  14. mx[i][j]=max(mx[i][j-1],mx[i+p][j-1]);
  15. mn[i][j]=min(mn[i][j-1],mn[i+p][j-1]);
  16. }
  17. }
  18. }
  19. int sol(int x,int y)
  20. {
  21. int p=log2(y-x+1.0);
  22. int mxx=max(mx[x][p],mx[y-(1<<p)+1][p]);
  23. int mnn=min(mn[x][p],mn[y-(1<<p)+1][p]);
  24. return mxx-mnn;
  25. }
  26. int main()
  27. {
  28. int t;
  29. scanf("%d",&t);
  30. while(t--)
  31. {
  32. scanf("%d%d",&n,&k);
  33. for(int i=1;i<=n;i++)
  34. {
  35. scanf("%d",&a[i]);
  36. mx[i][0]=mn[i][0]=a[i];
  37. }
  38. ST();
  39. long long ans=0;
  40. for(int i=1;i<=n;i++)
  41. {
  42. int l=i,r=n;
  43. while(l<=r)
  44. {
  45. int mid=(l+r)>>1;
  46. if(sol(i,mid)<k) l=mid+1;
  47. else
  48. r=mid-1;
  49. }
  50. ans += (r * 1LL - i + 1);
  51. }
  52. cout<<ans<<endl;
  53. }
  54. return 0;
  55. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注