[关闭]
@wsndy-xx 2018-09-12T19:56:27.000000Z 字数 2169 阅读 828

noip2017列队 - resolve

题解


的矩阵,每个元素 的标号为 , 每次给出 , 表示将查询此时处在 列元素的标号,并且删除此元素,接下来 行, 列以后的元素左移, 列, 行以后的元素前移,显然此时 空,将原先删除的 元素放到
输出每次查询


首先考虑一条链的情况
线段树维护 序列
列的元素放到最后
不考虑元素左移的情况(一条链只存在左移),这样的话如果一个元素被放到最后的位置,只需将第 变为 , 并且在线段树的最后的位置加入一个 , 这样的话区间的和就是区间元素的个数

列:
元素:1 2 3 4 5 6
维护:1 1 1 1 1 1
将第 3 列的数放到序列的最后
1 - 3 4 5 6 2
1 0 1 1 1 1 1
将第 3 列的数放到序列的最后
首先找到第 列的数,也就是第 的位置,此时这个位置的数为
1 - 3 - 5 6 2 4
1 0 1 0 1 1 1 1

推广
对每一行的前 个元素开一颗线段树, 对最后一列开一颗线段树。
总共 颗线段树
每颗线段树都维护这样的 序列代表每个位置元素的有无

操作:
对于询问是否是 列的有关询问分类处理
现在需要查询绿色区域,那么就将绿色区域的元素放到2号区域,相应地,绿色区域变成 , 2号区域变成 , 然后查询 行的元素放到1号区域,相应地红色区域变成 , 1号区域变为

如何处理元素的编号:
将每个点的编号记录下来是不可能的,这里只记录位置发生过改变的元素的编号,由于不会发生移动操作,所以没有改变的元素的编号是可以由行列的坐标得到的。只有发生元素的移动才会记录元素的编号。
对于空间
动态开节点

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int N = 6e5 + 10;
  4. int Lson[N * 30], Rson[N * 30], Size[N * 30], Root[N];
  5. int Long[N];
  6. int Seg;
  7. int n, m, q;
  8. int Len;
  9. #define LL long long
  10. LL Data[N * 30];
  11. #define gc getchar()
  12. inline int read() {int x = 0; char c = gc; while(c < '0' || c > '9') c = gc;
  13. while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc; return x;}
  14. #undef gc
  15. int now_x, now_y;
  16. int Calc_size(int l, int r) {
  17. if(now_y != m) {
  18. if(r > Long[now_x]) return Long[now_x] - l + 1;
  19. else return r - l + 1;
  20. } else {
  21. if(r > Long[n + 1]) return Long[n + 1] - l + 1;
  22. else return r - l + 1;
  23. }
  24. }
  25. LL Ans;
  26. void Poi_A(int &rt, int l, int r, int x) {
  27. if(!rt) {
  28. rt = ++ Seg;
  29. Size[rt] = Calc_size(l, r);
  30. }
  31. Size[rt] --;
  32. if(l == r) {
  33. if(Data[rt] != 0) Ans = Data[rt];
  34. else {
  35. if(now_y != m) Ans = (1ll * now_x - 1) * m + r;
  36. else Ans = 1ll * r * m;
  37. }
  38. return ;
  39. }
  40. int mid = (l + r) >> 1;
  41. int s_ = Lson[rt] ? Size[Lson[rt]] : Calc_size(l, mid);
  42. if(x <= s_) Poi_A(Lson[rt], l, mid, x);
  43. else if(Lson[rt]) Poi_A(Rson[rt], mid + 1, r, x - Size[Lson[rt]]);
  44. else Poi_A(Rson[rt], mid + 1, r, x - Calc_size(l, mid));
  45. }
  46. void Poi_G(int &rt, int l, int r, int x, LL val) {
  47. if(!rt) {
  48. rt = ++ Seg;
  49. Size[rt] = Calc_size(l, r);
  50. } else Size[rt] ++;
  51. if(l == r) {
  52. Data[rt] = val;
  53. return ;
  54. }
  55. int mid = (l + r) >> 1;
  56. if(x <= mid) Poi_G(Lson[rt], l, mid, x, val);
  57. else Poi_G(Rson[rt], mid + 1, r, x, val);
  58. }
  59. int main() {
  60. n = read(), m = read(), q = read();
  61. Len = max(n, m) + q;
  62. for(int i = 1; i <= n; i ++) Long[i] = m - 1;
  63. Long[n + 1] = n;
  64. for(; q; q --) {
  65. int xx = read(), yy = read();
  66. now_x = xx, now_y = yy;
  67. if(yy == m) {
  68. Poi_A(Root[n + 1], 1, Len, xx);
  69. cout << Ans << "\n";
  70. Poi_G(Root[n + 1], 1, Len, ++ Long[n + 1], Ans);
  71. } else {
  72. Poi_A(Root[xx], 1, Len, yy);
  73. cout << Ans << "\n";
  74. LL Ans1 = Ans;
  75. now_y = m;
  76. Poi_A(Root[n + 1], 1, Len, xx);
  77. now_y = yy;
  78. Poi_G(Root[xx], 1, Len, ++ Long[xx], Ans);
  79. now_y = m;
  80. Poi_G(Root[n + 1], 1, Len, ++ Long[n + 1], Ans1);
  81. }
  82. }
  83. return 0;
  84. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注