• POJ 3109 Inner Vertices 离散化+树状数组


    一、题目大意

    围棋棋盘,如果某个坐标上下左右的四个方向都存在棋子,那么ans+1,根据输入的棋子数量,求出ans的数量。

    二、解题思路

    题目中有说到如果程序不会结束,那么输出-1,这其实是无源之水,根本不会发生。

    我们可以一列一列的循环,然后针对列建立一个树状数组(线段树也行,树状数组更快)

    坐标比较大,需要离散化(离散化就是把有效坐标排好序去重放在数组里,然后用原坐标对应数字再数组元素的顺序来替换掉原坐标的算法,可以参阅《挑战程序设计》第三章-常用技巧精选,或者可以参考鄙人AOJ0531的拙作题解)本题目每个输入的棋子x和y是有效坐标,其余坐标均无效,因为没有棋子的行或列一定无法让ans+1。

    之后根据列来排序,列一样的,就根据行来排序(pair默认的就行,first列,second行)

    然后记录下每一行的最后一个棋子的坐标(可以定一个数组,初值设置1或0,循环一次所有的棋子,更新到每一行的最大列即可)

    然后,同时记录一个bool型的标记数组,来代表某一行是否前面已经有个棋子,如下图

    循环每一列的时候,把当前元素和当前列上一个元素之间的元素集体+1(树状数组操作)update(上一个元素的列+1,当前元素列-1,1)这里需要判断下上一个的列+1和当前列-1的大小,如果大于等于那就不要更新了

    同时遇到每一行第一个棋子时,要把这一行标记上,然后这一行的位置更新到0(更新到0是因为这一行之前左边没有棋子,如果左边没有棋子,那么这些+1的情况,即便上下有子也不应该记录到答案里,为的就是防止下图中红色箭头的位置被错误记录了),这样下次再碰到这一行的棋子,就可以代表两者之间的部分位置可以加到答案里。

    然后更新到每一行最后一列的时候(这里可以通过之前记录的行最大列的数组来判断是不是最后一列),如果这一行之前没有被标记过,即这一行的最后一个棋子左边没有棋子,那么这一行+1的那些坐标不算数,上下有子,右边也有,但是左边没有那就不行,直接continue。

    如果这一行标记过,那那表左边有棋子,同时循环到的这一行的最后一个棋子是它右边的,然后更新树状数组时的区间边界是它上下的,那么树状数组求出这一行的数量,要加到ans里,我这个思路就是如下图所示,每一列右边的一些数子,就是遇到走过某一列的时候树状数组渲染到正常的样子(非树形求和的那种),然后红色的箭头的就代表走到某一行最后一列了增加ans,

    表达的不清晰,见谅!

    三、代码

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. typedef long long ll;
    6. typedef pair<int, int> P;
    7. P num[100010];
    8. ll bit0[131080], bit1[131080], ans;
    9. int x[100010], y[100010], xLen, yLen, n, n_, maxCol[100010];
    10. bool activeRow[100010];
    11. void input()
    12. {
    13. for (int i = 1; i <= n_; i++)
    14. {
    15. scanf("%d%d", &num[i].first, &num[i].second);
    16. x[i] = num[i].first;
    17. y[i] = num[i].second;
    18. activeRow[i] = false;
    19. maxCol[i] = 1;
    20. }
    21. sort(x + 1, x + (1 + n_));
    22. sort(y + 1, y + (1 + n_));
    23. }
    24. void compress()
    25. {
    26. xLen = 1;
    27. yLen = 1;
    28. for (int i = 2; i <= n_; i++)
    29. {
    30. if (x[xLen] != x[i])
    31. {
    32. x[++xLen] = x[i];
    33. }
    34. if (y[yLen] != y[i])
    35. {
    36. y[++yLen] = y[i];
    37. }
    38. }
    39. for (int i = 1; i <= n_; i++)
    40. {
    41. num[i].first = lower_bound(x + 1, x + (xLen + 1), num[i].first) - x;
    42. num[i].second = lower_bound(y + 1, y + (yLen + 1), num[i].second) - y;
    43. if (maxCol[num[i].second] < num[i].first)
    44. {
    45. maxCol[num[i].second] = num[i].first;
    46. }
    47. }
    48. }
    49. void init()
    50. {
    51. n = 131072;
    52. for (int i = 0; i <= n; i++)
    53. {
    54. bit0[i] = 0LL;
    55. bit1[i] = 0LL;
    56. }
    57. }
    58. void updateBit0(int r, ll v)
    59. {
    60. if (r <= 0)
    61. {
    62. return;
    63. }
    64. for (int i = r; i <= n; i = i + (i & (-i)))
    65. {
    66. bit0[i] = bit0[i] + v;
    67. }
    68. }
    69. void updateBit1(int r, ll v)
    70. {
    71. if (r <= 0)
    72. {
    73. return;
    74. }
    75. for (int i = r; i <= n; i = i + (i & (-i)))
    76. {
    77. bit1[i] = bit1[i] + v;
    78. }
    79. }
    80. ll queryBit0(int r)
    81. {
    82. ll sum = 0LL;
    83. for (int i = r; i > 0; i = i - (i & (-i)))
    84. {
    85. sum = sum + bit0[i];
    86. }
    87. return sum;
    88. }
    89. ll queryBit1(int r)
    90. {
    91. ll sum = 0LL;
    92. for (int i = r; i > 0; i = i - (i & (-i)))
    93. {
    94. sum = sum + bit1[i];
    95. }
    96. return sum;
    97. }
    98. void update(int l, int r, ll v)
    99. {
    100. updateBit0(l, (-1LL) * v * ((ll)(l - 1)));
    101. updateBit0(r + 1, v * ((ll)r));
    102. updateBit1(l, v);
    103. updateBit1(r + 1, (-1LL) * v);
    104. }
    105. ll query(int l, int r)
    106. {
    107. ll allAmt = queryBit0(r);
    108. ll allAdd = queryBit1(r) * ((ll)r);
    109. ll leftAmt = queryBit0(l - 1);
    110. ll leftAdd = queryBit1(l - 1) * ((ll)(l - 1));
    111. return (allAmt + allAdd - leftAmt - leftAdd);
    112. }
    113. void solve()
    114. {
    115. sort(num + 1, num + (1 + n_));
    116. ans = 0LL;
    117. for (int i = 1; i <= n_; i++)
    118. {
    119. if (i > 1 && num[i - 1].first == num[i].first && (num[i - 1].second + 1) < num[i].second)
    120. {
    121. update(num[i - 1].second + 1, num[i].second - 1, 1LL);
    122. }
    123. if (maxCol[num[i].second] == num[i].first && !activeRow[num[i].second])
    124. {
    125. continue;
    126. }
    127. if (maxCol[num[i].second] == num[i].first && activeRow[num[i].second])
    128. {
    129. ans = ans + query(num[i].second, num[i].second);
    130. }
    131. if (!activeRow[num[i].second])
    132. {
    133. ll oldVal = query(num[i].second, num[i].second);
    134. update(num[i].second, num[i].second, (-1LL) * oldVal);
    135. activeRow[num[i].second] = true;
    136. }
    137. }
    138. }
    139. int main()
    140. {
    141. while (~scanf("%d", &n_))
    142. {
    143. input();
    144. compress();
    145. init();
    146. solve();
    147. ans = ans + ((ll)n_);
    148. printf("%lld\n", ans);
    149. }
    150. return 0;
    151. }

  • 相关阅读:
    openssl生成key和pem文件
    从零开始搭建自己的cli脚手架
    MybatisPlus【SpringBoot】 2 入门案例
    XMLHttpRequest是怎么实现的
    网络安全-Web端安全协议
    【机器学习】机器学习的重要方法——线性回归算法深度探索与未来展望
    智慧园区SaaS管理系统解决方案:赋能园区实现信息化、数字化管理
    微服务之架构演变
    【数据结构与算法】之多指针算法经典问题
    【JavaSE】多态
  • 原文地址:https://blog.csdn.net/qq_53038151/article/details/133512992