点分治题单

本文介绍了点分治算法在解决树形结构问题中的应用,包括求解点对距离、小于特定距离的点对数量等。通过二分查找和递归处理,实现了高效的解决方案,并提供了详细的代码实现,涉及了树的重心、子树距离信息统计等关键步骤。

点分治中重点需要注意:

  1. 统计ans的时候,一定要注意子树中的ans和当前根节点的ans的处理关系
  2. 切记要注意重心的处理

一、P3806 【模板】点分治1

思路:

  1. 将一颗子树的点到根的距离存入到一个栈中,这个栈维护当前重心的所有子树的距离信息
  2. 我们在得子树点到根信息后,我们在枚举进行距离的判断,我们判断完再进行信息的入栈。
    code:
/*
 * @Author: 0iq_love_zy
 * @LastEditTime: 2021-02-21 18:35:44
 * @优快云 blog: https://blog.youkuaiyun.com/acm_durante
 * @E-mail: 1055323152@qq.com
 * @ProbTitle: 
 */
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i, a, n) for (int i = a; i <= n; i++)
#define per(i, a, n) for (int i = n; i >= a; i--)
#define lowbit(x) ((x) & -(x))
#define lson p << 1 , l, mid 
#define rson p << 1 | 1, mid + 1, r
#define mem(a, b) memset(a, b, sizeof(a))
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
const double PI = acos(-1.0);
const int N = 2e4+5,M = 1e7+5;
int n,m,ask[105],cnt,head[N];
struct node{
   
   
    int v,w,net;
}e[N];
void add(int u,int v,int w){
   
   
    e[++cnt].v = v;
    e[cnt].w = w;
    e[cnt].net = head[u];
    head[u] = cnt;
}
int sz[N],sum,mx[N],root;
bool vis[N];

void get_root(int u,int fa){
   
   
    sz[u] = 1;
    mx[u] = 0;
    for(int i = head[u]; ~i ; i = e[i].net){
   
   
        int v = e[i].v;
        if(vis[v] || v == fa) continue;
        get_root(v,u);
        sz[u] += sz[v];
        mx[u] = max(mx[u],sz[v]);
    }
    mx[u] = max(mx[u],sum - mx[u]);
    if(mx[u] < mx[root]){
   
   
        root = u;
    }
}
int dis[N],dd[N],tot;
void get_dis(int u,int fa){
   
   
    dd[++tot] = dis[u];
    for(int i = head[u]; ~i ; i = e[i].net){
   
   
        int v = e[i].v, w = e[i].w;
        if(v == fa || vis[v]) continue;
        dis[v] = dis[u] + w;
        get_dis(v,u);
    }
}
queue<int>que;
bool tf[M],ans[M];
void dfz(int u,int fa){
   
   
    tf[0] = 1;
    que.push(0);
    vis[u] = 1;
    for(int i = head[u]; ~i ; i = e[i].net){
   
   //case1:经过u
        int v = e[i].v;
        if(v == fa || vis[v]) continue;
        dis[v] = e[i].w;
        tot = 0;
        get_dis(v,u);
        rep(j,1,tot)
            rep(z,1,m){
   
   
                if(ask[z] >= dd[j]) ans[z] |= tf[ask[z] - dd[j]];
            }
        rep(j
### 经典递归与分治算法例及解法 #### 斐波那契数列 斐波那契数列是一个经典的递归问。其定义如下: \[ F(n) = \begin{cases} 0 & n=0 \\ 1 & n=1 \\ F(n-1)+F(n-2) & n>1 \end{cases} \] ##### 递归实现 递归方法简直观,但效率较低,因为存在大量重复计算。 ```python def fibonacci_recursive(n): if n == 0: return 0 elif n == 1: return 1 else: return fibonacci_recursive(n - 1) + fibonacci_recursive(n - 2) ``` ##### 迭代实现 迭代方式通过循环逐步求解,避免了递归中的冗余计算,时间复杂度为 \(O(n)\)[^2]。 ```python def fibonacci_iterative(n): a, b = 0, 1 for _ in range(n): a, b = b, a + b return a ``` --- #### 归并排序(Merge Sort) 归并排序是一种典型的分治算法应用案例。它将数组分成两半分别排序后再合并。 ##### 实现代码 ```python def merge_sort(arr): if len(arr) <= 1: return arr mid = len(arr) // 2 left_half = merge_sort(arr[:mid]) # 左侧子数组递归排序 right_half = merge_sort(arr[mid:]) # 右侧子数组递归排序 return merge(left_half, right_half) def merge(left, right): result = [] while left and right: if left[0] < right[0]: result.append(left.pop(0)) else: result.append(right.pop(0)) result.extend(left or right) return result ``` 上述代码展示了如何利用分治的思想解决问[^3]。 --- #### 快速排序(Quick Sort) 快速排序也是一种基于分治思想的经典排序算法。它的核心在于选取一个基准值,将数组分为小于基准值的部分和大于基准值的部分,然后再对这两部分递归处理。 ##### 实现代码 ```python def quick_sort(arr): if len(arr) <= 1: return arr pivot = arr[len(arr) // 2] left = [x for x in arr if x < pivot] middle = [x for x in arr if x == pivot] right = [x for x in arr if x > pivot] return quick_sort(left) + middle + quick_sort(right) ``` --- #### 最近点对问 最近点对问是另一个常见的分治算法应用场景。给定平面上的一组点,找到距离最短的两个点。 ##### 解决思路 1. 将所有点按横坐标排序; 2. 对于每一步,递归地寻找左侧和右侧区域内的最小距离; 3. 合并阶段考虑跨越中间线的情况。 --- #### 汉诺塔问 汉诺塔问也是一个经典的递归例子。目标是从一根柱子上移动一系列盘子到另一根柱子,遵循以下规则: 1. 每次只能移动一个盘子; 2. 较大的盘子不能放在较小的盘子上面。 ##### 实现代码 ```python def hanoi_tower(n, source, target, auxiliary): if n == 1: print(f"Move disk 1 from {source} to {target}") return hanoi_tower(n - 1, source, auxiliary, target) print(f"Move disk {n} from {source} to {target}") hanoi_tower(n - 1, auxiliary, target, source) ``` --- #### 力扣经典目推荐 以下是力扣上的几道涉及递归与分治的经典目: 1. **LeetCode 53. Maximum Subarray** 使用分治策略可以高效解决最大子数组和问[^4]。 2. **LeetCode 973. K Closest Points to Origin** 应用分治思想优化查找最近点的过程。 3. **LeetCode 240. Search a 2D Matrix II** 基于矩阵特性设计高效的分治搜索方案。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值