• 点分治学习笔记 / 洛谷 P3806【点分治】


    分治算法实际上可以分成几个步骤:

    Step 1 \cal 1 1:将经过当前的根节点的路径处理好。

    Step 2 \cal 2 2:找到当前子树的重心

    Step 3 \cal 3 3:由于树可以自由变换根节点,所以用重心来替换根节点,进行优化。

    Step 4 \cal 4 4:删除根节点。

    Step 5 \cal 5 5:递归枚举儿子节点。

    由于某些原因,洛谷模板题需要提前预处理。

    #include 
    
    using namespace std;
    
    const int N = 1e4 + 10;
    int e[N << 1], ne[N << 1], w[N << 1], h[N], idx = 0;
    int q[N];
    bool vis[N], ans[N], jud[10000010];
    int mx[N], sz[N], td[N], dis[N];
    int n, m, root = 1, sumtree, cnt;
    
    int reader()
    {
      int opt = 1, x;
      char ch;
      while (!isdigit(ch = getchar()))
        if (ch == '-')
          opt = -1;
      x = ch - '0';
      while (isdigit(ch = getchar()))
        x = (x << 3) + (x << 1) + (ch ^ 48);
      return x * opt;
    }
    
    void init_edge()
    {
      memset (h, -1, sizeof h);
      idx = 0;
    }
    
    void add_edge(int u, int v, int c)
    {
      e[idx] = v;
      ne[idx] = h[u];
      w[idx] = c;
      h[u] = idx ++;
    }
    
    void get_bc(int u, int fa)
    {
      sz[u] = 1;
      mx[u] = 0;
      for (int i = h[u]; ~i; i = ne[i])
      {
        int v = e[i];
        if (v != fa && !vis[v])
        {
          get_bc(v, u);
          sz[u] += sz[v];
          mx[u] = max(mx[u], sz[v]);
        }
      }
      mx[u] = max(mx[u], sumtree - sz[u]);
      if (mx[u] < mx[root])
        root = u;
    }
    
    void get_real_bc()
    {
      get_bc(1, 0);
      get_bc(root, 0);
    }
    
    void get_dis(int u, int fa)
    {
      td[++ cnt] = dis[u];
      for (int i = h[u]; ~i; i = ne[i])
      {
        int v = e[i];
        if (!vis[v] && v != fa)
        {
          dis[v] = dis[u] + w[i];
          get_dis(v, u);
        }
      }
    }
    
    void solve(int u)
    {
      queue <int> que;
      for (int i = h[u]; ~i; i = ne[i])
      {
        int v = e[i];
        if (!vis[v])
        {
          cnt = 0;
          dis[v] = w[i];
          get_dis(v, u);
          for (int j = 1; j <= cnt; j ++)
            for (int k = 1; k <= m; k ++)
              if (q[k] >= td[j])
                ans[k] |= jud[q[k] - td[j]];
          for (int j = 1; j <= cnt; j ++)
            if (td[j] <= 1e7)
              que.push(td[j]);
          for (int j = 1; j <= cnt; j ++)
            if (td[j] <= 1e7)
              jud[td[j]] = true;
        }
      }
      while (que.size())
      {
        jud[que.front()] = false;
        que.pop();
      }
    }
    
    void initfs(int u)
    {
      vis[u] = jud[0] = true;
      solve(u);
      for (int i = h[u]; ~i; i = ne[i])
      {
        int v = e[i];
        if (!vis[v])
        {
          mx[root = 0] = sumtree = sz[v];
          get_bc(v, 0);
          get_bc(root, 0);
          initfs(root);
        }
      }
    }
    
    int main()
    {
      init_edge();
      n = reader(), m = reader();
      for (int i = 1; i < n; i ++)
      {
        int u = reader(), v = reader(), w = reader();
        add_edge(u, v, w);
        add_edge(v, u, w);
      }
      for (int i = 1; i <= m; i ++)
        q[i] = reader();
      mx[root = 0] = sumtree = n;
      get_real_bc();
      initfs(root);
      for (int i = 1; i <= m; i ++)
        if (ans[i])
          cout << "AYE\n";
        else
          cout << "NAY\n";
      return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
  • 相关阅读:
    springboot基于web模式的师资管理系统的设计与实现毕业设计源码040928
    SSM之spring注解式缓存redis
    多卡服务器使用
    DM8:生成DM AWR报告
    GSEA -- 学习记录
    这个怎么编写,按图中的要求输出形式
    多线程知识 汇总(1)
    猴赛雷 ! 上次我见过这么厉害的安全测试实战演练还是上次!
    【JVM基础】堆
    2-3.基金的估值,费用与会计
  • 原文地址:https://blog.csdn.net/lxylluvio/article/details/126609579