Codeforces 1101D 点分治

Myth丶恋晨 2021-12-12 02:07 345阅读 0赞

题意:有一颗树,每个点有一个点权,边权都是1,问路径上的所有点的gcd不是1的最长路径是多少?

思路:之前补这道题的时候,用分解质因数 + 树形DP做的,其实用点分治可以更暴力一点。对于这类统计树上路径的问题,点分治是一种通用,高效的解法。对于所有的路径,无非两种情况:经过某个点,不经过某个点,我们对于每个点统计的相当于是经过该点的路径的信息。点分治为以下几步:1:找重心。2:以找到的重心为根,解决经过该点的路径的问题。3:递归的找其它子树的重心,解决问题。找经过该点的路径时,直接搜索求gcd,所有说非常暴力无脑。找到之后暴力合并。复杂度应该是O(n * (log(n) ^ 2));

代码:

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. const int maxn = 200010;
  4. vector<int> G[maxn];
  5. map<int, int> mp, tmp;
  6. map<int, int>::iterator it1, it2;
  7. bool v[maxn];
  8. int sz[maxn], tot, mx, root, a[maxn], ans;
  9. void add(int x, int y) {
  10. G[x].push_back(y);
  11. G[y].push_back(x);
  12. }
  13. void get_root(int x, int fa) {
  14. sz[x] = 1;
  15. int max_part = 0;
  16. for (auto y : G[x]) {
  17. if(y == fa || v[y]) continue;
  18. get_root(y, x);
  19. sz[x] += sz[y];
  20. max_part = max(max_part, sz[y]);
  21. }
  22. max_part = max(max_part, tot - sz[x]);
  23. if(max_part < mx) {
  24. mx = max_part;
  25. root = x;
  26. }
  27. }
  28. void get_ans(int x, int dep, int fa, int z) {
  29. if(z == 1) return;
  30. tmp[z] = max(tmp[z], dep);
  31. for (auto y : G[x]) {
  32. if(v[y] || y == fa) continue;
  33. get_ans(y, dep + 1, x, __gcd(z, a[y]));
  34. }
  35. }
  36. void solve(int x) {
  37. mp.clear();
  38. mp[a[x]] = 1;
  39. for (auto y : G[x]) {
  40. if(v[y]) continue;
  41. tmp.clear();
  42. get_ans(y, 1, x, __gcd(a[x], a[y]));
  43. for (it1 = mp.begin(); it1 != mp.end(); it1++) {
  44. for (it2 = tmp.begin(); it2 != tmp.end(); it2++) {
  45. if(__gcd(it1 -> first, it2 -> first) != 1) {
  46. ans = max(ans, (it1 -> second) + (it2 -> second));
  47. }
  48. }
  49. }
  50. for (it2 = tmp.begin(); it2 != tmp.end(); it2++) {
  51. mp[it2 -> first] = max(mp[it2 -> first], (it2 -> second) + 1);
  52. }
  53. }
  54. }
  55. void div(int x) {
  56. v[x] = 1;
  57. solve(x);
  58. for (auto y : G[x]) {
  59. if(v[y]) continue;
  60. tot = sz[y];
  61. mx = 1e6;
  62. get_root(y, x);
  63. div(root);
  64. }
  65. }
  66. int main() {
  67. int n, x, y;
  68. scanf("%d", &n);
  69. for (int i = 1; i <= n; i++) {
  70. scanf("%d", &a[i]);
  71. if(a[i] > 1) ans = 1;
  72. }
  73. for (int i = 1; i < n; i++) {
  74. scanf("%d%d", &x, &y);
  75. add(x, y);
  76. }
  77. tot = n;
  78. mx = 1e6;
  79. get_root(1, -1);
  80. div(root);
  81. printf("%d\n", ans);
  82. }

  

转载于:https://www.cnblogs.com/pkgunboat/p/11158772.html

发表评论

表情:
评论列表 (有 0 条评论,345人围观)

还没有评论,来说两句吧...

相关阅读

    相关 CodeForces1214D

    [CodeForces1214D][] 这个题据我所知有两种比较优秀的做法. 第一种是\\(DP\\)统计每个点的路径数,然后找出必经点,再从必经点开始\\(bfs\\

    相关 Codeforces 496D

    题意 -------------------- 进行若干场比赛,每次比赛两人对决,赢的人得到1分,输的人不得分,先得到t分的人获胜,开始下场比赛,某个人率先赢下s场比赛

    相关 分治

      [传送门][Link 1](洛谷) UPDATE:关于代码中时间复杂度的更正——在代码中每一次都要通过遍历一遍询问来得到答案,所以时间复杂度是O(NMlogN), !

    相关 Codeforces 1101D 分治

    题意:有一颗树,每个点有一个点权,边权都是1,问路径上的所有点的gcd不是1的最长路径是多少? 思路:之前补这道题的时候,用分解质因数 + 树形DP做的,其实用点分治可以更暴