• (枚举 + 树上倍增)Codeforces Round 900 (Div. 3) G


    Problem - G - Codeforces

    题意:

    思路:

    首先,目标值和结点权值是直接联系的,最值不可能直接贪心,一定是考虑去枚举一些东西,依靠这种枚举可以遍历所有的有效情况,思考的方向一定是枚举

    如果去直接在链上枚举的话, 复杂度是O(nq),肯定不行

    注意到一条路径上的前缀或值不会超过 logV个,因此考虑枚举前缀或值

     

    关于每次跳使前缀或值变化的最深的点,我是这样理解的

    如果考虑在链上枚举,如果前缀或值不变,那么这样的枚举是无效的,我们直接考虑跳着枚举,只枚举所有有效情况

    关于怎么跳其实可以参考树上倍增往上跳的跳法,记录一个数组指向下一个结点,在dfs上维护即可,有点像在树链上DP

    Code:

    1. #include
    2. #define int long long
    3. constexpr int N = 2e5 + 10;
    4. std::vector<int> adj[N];
    5. int n;
    6. int a[N];
    7. int dep[N];
    8. int f[N][33], s[N][33], lst[N][33];
    9. void dfs(int u, int fa) {
    10. dep[u] = dep[fa] + 1;
    11. f[u][0] = fa;
    12. for (int j = 1; j <= 30; j ++) f[u][j] = f[f[u][j - 1]][j - 1];
    13. int val = a[u];
    14. for (int j = 30; j >= 0; j --) {
    15. if (!((val >> j) & 1)) {
    16. lst[u][j] = lst[fa][j];
    17. s[u][j] = s[fa][j];
    18. }else {
    19. lst[u][j] = u;
    20. s[u][j] = s[fa][j] + 1;
    21. }
    22. }
    23. for (auto v : adj[u]) {
    24. if (v == fa) continue;
    25. dfs(v, u);
    26. }
    27. }
    28. int lca(int u, int v) {
    29. if (dep[u] < dep[v]) std::swap(u, v);
    30. for (int j = 30; j >= 0; j --) {
    31. if (dep[f[u][j]] >= dep[v]) {
    32. u = f[u][j];
    33. }
    34. }
    35. if (u == v) return u;
    36. for (int j = 30; j >= 0; j --) {
    37. if (f[u][j] != f[v][j]) {
    38. u = f[u][j];
    39. v = f[v][j];
    40. }
    41. }
    42. return f[u][0];
    43. }
    44. int calc(int x, int y, int lca) {
    45. int res = 0;
    46. for (int j = 0; j <= 30; j ++) {
    47. if (s[x][j] + s[y][j] - s[lca][j] - s[f[lca][0]][j]) res ++;
    48. }
    49. return res;
    50. }
    51. void solve() {
    52. std::cin >> n;
    53. for (int i = 1; i <= n; i ++) {
    54. adj[i].clear();
    55. dep[i] = 0;
    56. for (int j = 30; j >= 0; j --) {
    57. f[i][j] = s[i][j] = lst[i][j] = 0;
    58. }
    59. }
    60. for (int i = 1; i <= n; i ++) std::cin >> a[i];
    61. for (int i = 1; i <= n - 1; i ++) {
    62. int u, v;
    63. std::cin >> u >> v;
    64. adj[u].push_back(v);
    65. adj[v].push_back(u);
    66. }
    67. dfs(1, 0);
    68. int q;
    69. int ans = 0;
    70. std::cin >> q;
    71. while(q --) {
    72. int x, y;
    73. std::cin >> x >> y;
    74. int cur = x, val = a[x];
    75. ans = 0;
    76. while(1) {
    77. int nxt = 0, mx = 0;
    78. ans = std::max(ans, calc(x, cur, lca(x, cur)) + calc(cur, y, lca(cur, y)));
    79. for (int j = 30; j >= 0; j --) {
    80. if (!((val >> j) & 1)) {
    81. if (dep[lst[cur][j]] >= dep[lca(x, y)]) {
    82. if (dep[lst[cur][j]] > mx) {
    83. mx = dep[lst[cur][j]];
    84. nxt = lst[cur][j];
    85. }
    86. }
    87. }
    88. }
    89. if (!mx) break;
    90. val |= a[nxt];
    91. cur = nxt;
    92. }
    93. cur = y, val = a[y];
    94. while(1) {
    95. int nxt = 0, mx = 0;
    96. ans = std::max(ans, calc(x, cur, lca(x, cur)) + calc(cur, y, lca(cur, y)));
    97. for (int j = 30; j >= 0; j --) {
    98. if (!((val >> j) & 1)) {
    99. if (dep[lst[cur][j]] >= dep[lca(x, y)]) {
    100. if (dep[lst[cur][j]] > mx) {
    101. mx = dep[lst[cur][j]];
    102. nxt = lst[cur][j];
    103. }
    104. }
    105. }
    106. }
    107. if (!mx) break;
    108. val |= a[nxt];
    109. cur = nxt;
    110. }
    111. std::cout << ans << " ";
    112. }
    113. std::cout << "\n";
    114. }
    115. signed main() {
    116. std::ios::sync_with_stdio(false);
    117. std::cin.tie(nullptr);
    118. int t = 1;
    119. std::cin >> t;
    120. while(t --) {
    121. solve();
    122. }
    123. return 0;
    124. }

  • 相关阅读:
    国外Twilio 发送sms短信
    QT软件开发中的图标设置与好用的图标网站
    【基于C的排序算法】归并排序
    基于协同过滤算法的图书推荐系统设计与实现
    刚开始做斗音掌握这5点至少让你少走半年弯路
    CVE-2022-42889 Apache Commons Text远程代码执行漏洞复现
    [附源码]SSM计算机毕业设计江苏策腾智能科技公司人事管理系统JAVA
    vue中FileReader 的使用
    操作系统-《王道 操作系统》
    mysql查询最近7天 每天销售额 统计销售额
  • 原文地址:https://blog.csdn.net/weixin_62528401/article/details/133531640