[关闭]
@sensitive-cs 2017-05-13T06:46:05.000000Z 字数 3282 阅读 974

2017.5.8训练题

题解


B - A Corrupt Mayor's Performance Art
题意:
有一堵墙,分为n块,开始的时候每块颜色都是2,之后会针对由a到b的色块进行染色,颜色共有30,然后其中会有查询a到b的块由哪些颜色的操作,并且按照升序输出。
思路:
一开始按照区间修改的套路去做,但是很明显的颜色修改不可能覆盖每一块,会有bug,后来看题解知道用状态压缩的方式去表示是否有这种颜色,位运算果然是美妙的。
注意每次build以及update的时候最后要加上pushup。
然后在update中以及query中pushdown永远在递归前面。
代码:

  1. #include <stdio.h>
  2. #include <string.h>
  3. const int mx = 1000005;
  4. int cl[mx << 2];
  5. int add[mx << 2];
  6. bool v[35];
  7. void pushup(int rt)
  8. {
  9. cl[rt] = cl[rt << 1 | 1] | cl[rt << 1];
  10. }
  11. void pushdown(int rt)
  12. {
  13. if (add[rt])
  14. {
  15. //cl[rt] = add[rt];
  16. add[rt << 1] = add[rt];
  17. add[rt << 1|1] = add[rt];
  18. cl[rt << 1] = add[rt];
  19. cl[rt << 1|1] = add[rt];
  20. add[rt] = 0;
  21. }
  22. }
  23. void build(int rt,int l,int r,int k)
  24. {
  25. if (l == r)
  26. {
  27. cl[rt] = k;
  28. return;
  29. }
  30. int m = (l + r) >> 1;
  31. build(rt << 1,l,m,k);
  32. build(rt << 1|1,m+1,r,k);
  33. pushup(rt);
  34. }
  35. void update(int rt,int ll,int rr,int k,int l,int r)
  36. {
  37. if (l >= ll && r <= rr)
  38. {
  39. cl[rt] = 1 << (k - 1);
  40. add[rt] = 1 << (k - 1);
  41. return;
  42. }
  43. int m = (l + r) >> 1;
  44. pushdown(rt);
  45. if (ll <= m)
  46. {
  47. update(rt << 1,ll,rr,k,l,m);
  48. }
  49. if (rr > m)
  50. {
  51. update(rt << 1|1,ll,rr,k,m+1,r);
  52. }
  53. pushup(rt);
  54. }
  55. long long query(int rt,int ll,int rr,int l,int r)
  56. {
  57. if (l >= ll && r <= rr)
  58. {
  59. return cl[rt];
  60. }
  61. int m = (l + r) >> 1;
  62. pushdown(rt);
  63. long long ret = 0;
  64. if (ll <= m)
  65. {
  66. ret |= query(rt << 1,ll,rr,l,m);
  67. }
  68. if (rr > m)
  69. {
  70. ret |= query(rt << 1|1,ll,rr,m+1,r);
  71. }
  72. return ret;
  73. }
  74. int main()
  75. {
  76. int m,n;
  77. while (scanf("%d%d",&n,&m) != EOF)
  78. {
  79. if (m == 0 && n == 0) break;
  80. memset(cl,0,sizeof(cl));
  81. memset(add,0,sizeof(add));
  82. memset(v,0,sizeof(v));
  83. build(1,1,n,2);
  84. for (int i = 0;i < m;i++)
  85. {
  86. char s[5];
  87. int a,b,c;
  88. scanf("%s",s);
  89. if (s[0] == 'P')
  90. {
  91. scanf("%d%d%d",&a,&b,&c);
  92. update(1,a,b,c,1,n);
  93. }
  94. if (s[0] == 'Q')
  95. {
  96. memset(v,0,sizeof(v));
  97. scanf("%d%d",&a,&b);
  98. long long ans = query(1,a,b,1,n);
  99. for (int j = 0;j < 30;j++)
  100. {
  101. if (ans & (1 << j)) v[j+1] = 1;
  102. }
  103. bool flag = 0;
  104. for (int j = 1;j <= 30;j++)
  105. {
  106. if (v[j])
  107. {
  108. if (!flag)
  109. {
  110. printf("%d",j);
  111. flag = 1;
  112. }
  113. else
  114. printf(" %d",j);
  115. }
  116. }
  117. printf("\n");
  118. }
  119. }
  120. }
  121. return 0;
  122. }

A - Hotel
题意:
一个旅馆有n间房间,最开始这些房间是空的。两种操作,第一种是a人问是否能住进来,这是查询是否有a个连续的房间,若有,则返回起点编号最小的区间的起点,并且把这些房间占用了。第二种操作是将起点为a,区间长度为
b的房间清空。
思路:
线段树的区间合并,非结构体版本,以后就用这个当板子。
主要用了ls,rs,ms三个变量表示当前区间的左连续长度,右连续长度和总连续长度。然后比较重要的函数是pushdown和pushup。特别注意横跨两个区间的长度是要单独讨论的。还得找题来做做。
代码:

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <algorithm>
  4. using namespace std;
  5. #define lson l,mid,rt << 1
  6. #define rson mid + 1,r,rt << 1|1
  7. const int inf = 55555;
  8. int ls[inf << 2],rs[inf << 2],ms[inf << 2];
  9. int add[inf << 2];
  10. void pushdown(int rt,int len)
  11. {
  12. if (add[rt] != -1)
  13. {
  14. add[rt << 1] = add[rt << 1|1] = add[rt];
  15. ms[rt << 1] = ls[rt << 1] = rs[rt << 1] = add[rt] ? 0 : len - (len >> 1);
  16. ms[rt << 1|1] = ls[rt << 1|1] = rs[rt << 1|1] = add[rt] ? 0 : (len >> 1);
  17. add[rt] = -1;
  18. }
  19. }
  20. void pushup(int rt,int len)
  21. {
  22. ls[rt] = ls[rt << 1];
  23. rs[rt] = rs[rt << 1|1];
  24. if (ls[rt] == len - (len >> 1)) ls[rt] += ls[rt << 1|1];
  25. if (rs[rt] == (len >> 1))rs[rt] += rs[rt << 1];
  26. ms[rt] = max(ms[rt << 1],ms[rt << 1|1]);
  27. ms[rt] = max(ms[rt],rs[rt << 1] + ls[rt << 1|1]);
  28. }
  29. void build(int l,int r,int rt)
  30. {
  31. add[rt] = -1;
  32. ls[rt] = rs[rt] = ms[rt] = r - l + 1;
  33. if (l == r) return;
  34. int mid = (l + r) >> 1;
  35. build(lson);
  36. build(rson);
  37. }
  38. void update(int ll,int rr,int k,int l,int r,int rt)
  39. {
  40. if (l >= ll && r <= rr)
  41. {
  42. add[rt] = k;
  43. ms[rt] = rs[rt] = ls[rt] = k ? 0 : (r - l + 1);
  44. return;
  45. }
  46. pushdown(rt,r - l + 1);
  47. int mid = (l + r) >> 1;
  48. if (ll <= mid) update(ll,rr,k,lson);
  49. if (rr > mid) update(ll,rr,k,rson);
  50. pushup(rt,r-l+1);
  51. }
  52. int query(int w,int l,int r,int rt)
  53. {
  54. if (l == r) return l;
  55. pushdown(rt,r - l + 1);
  56. int mid = (l + r) >> 1;
  57. if (ms[rt << 1] >= w)
  58. return query(w,lson);
  59. else if (rs[rt << 1] + ls[rt << 1|1] >= w)
  60. return mid - rs[rt << 1] + 1;
  61. else
  62. return query(w,rson);
  63. }
  64. int main()
  65. {
  66. int m,n;
  67. scanf("%d%d",&n,&m);
  68. build(1,n,1);
  69. while (m--)
  70. {
  71. int a,b,c;
  72. scanf("%d",&a);
  73. if (a == 1)
  74. {
  75. scanf("%d",&b);
  76. if (ms[1] < b)
  77. printf("0\n");
  78. else
  79. {
  80. int t = query(b,1,n,1);
  81. printf("%d\n",t);
  82. update(t,t+b-1,1,1,n,1);
  83. }
  84. }
  85. else
  86. {
  87. scanf("%d%d",&b,&c);
  88. update(b,b + c - 1,0,1,n,1);
  89. }
  90. }
  91. return 0;
  92. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注