Walk

本文探讨了一道关于树形结构的问题,即寻找特定长度路径上边权值的最大公约数。通过巧妙地利用边的权值特性进行预处理,并采用枚举策略配合树的最长路径搜索,最终实现了高效求解。

【问题描述】
给定一棵n个节点的树,每条边的长度为 1,同时有一个权值
w。定义一条路径的权值为路径上所有边的权值的最大公约数。现在
对于任意i∈[1,n],求树上所有长度为 i的简单路径中权值最大的
是多少。如果不存在长度为 i的路径,则第 i行输出 0。
【输入格式】
第一行,一个整数 n,表示树的大小。
接下来n-1行,每行三个整数u,v,w,表示u,v间存在一条权值
为w的边。
【输出格式】
对于每种长度,输出一行,表示答案。
【样例输入】
3
1 2 3
1 3 9
【样例输出】
9
3
0
【数据范围及约定】
对于30%的数据,n≤1000。
对于额外30%的数据,w≤100。
对于100%的数据,n≤4*10^5,1≤u,v≤n,w≤10^6。

分析:
树上的操作,
嗯很好,我们要在边上做文章

考虑一下gcd的性质,
我们不需要什么厉害的结论
gcd(a,b)<=min(a,b) 显然吧

考虑边的取值不大,可以枚举一下gcd
假设枚举的gcd是i
那么什么样的路径可以使答案=i哩
当然是权值>i的边啦
废话。。。光是权值大没有用啊,ta还要有i这个因子啊
换句话说就是权值要是i的倍数
这样我们就可以在枚举gcd的时候,
加入相应的边,找到一条树上的最长路径,更新答案,

嗯,好像已经很完美了
等等,我们怎么在这么多边中找到一个特定权值的所有变呢
难道要O(n)遍历吗
显然不行,
这里就有一个小技巧了:
平常我们在加边的时候,大概都是这么写:

void add(int u,int w,int z)
{
    tot++;
    way[tot].x=u;
    way[tot].y=w;
    way[tot].v=z;
    way[tot].nxt=st[u];
    st[u]=tot;
}

st数组是以每一个起点为端点的所有边的起点值
那么我们能不能以权值为关键字呢
当然可以:有想法就有未来!!!
那么存边的时候就变成了这样:

void Add(int u,int w,int z)
{  //用权值当做关键字 
    tt++;
    way[tt].x=u;
    way[tt].y=w;
    way[tt].nxt=sta[z];
    sta[z]=tt;
}
这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>

using namespace std;

const int N=400005;
struct node{
    int x,y,nxt;
};
node e[N],way[N<<1];
int st[N],sta[1000010],tt=0,tot=0;
int p[N<<1],num=0;  //判重
int ans[N],mxlen,mx,n,link[N<<1]; 

void Add(int u,int w,int z)  //用权值当做关键字
{
    tt++;
    e[tt].x=u;e[tt].y=w;e[tt].nxt=sta[z];sta[z]=tt;
    //单项加边即可 
}

void add(int u,int w)
{
    tot++;
    way[tot].x=u;way[tot].y=w;way[tot].nxt=st[u];st[u]=tot;link[tot]=u;
    tot++;
    way[tot].x=w;way[tot].y=u;way[tot].nxt=st[w];st[w]=tot;link[tot]=w;
    //link的意思好像就是每条边的起点,不知道ta存在的意义是什么 
}

int dfs(int now)  //找树上最长路径 
{
    p[now]=num;  //visit;
    int mxson=0;
    for (int i=st[now];i;i=way[i].nxt)
        if (p[way[i].y]!=num)  //not visit
        {
            int r=dfs(way[i].y);
            mxlen=max(mxlen,r+mxson+1);
            mxson=max(mxson,r+1);
        }
    return mxson;
}

int main()
{
    scanf("%d",&n);
    for (int i=1;i<n;i++)
    {
        int u,w,z;
        scanf("%d%d%d",&u,&w,&z);
        mx=max(mx,z); //找到最大权值  
        Add(u,w,z);
    }
    for (int i=1;i<=mx;i++) //mx是gcd上界 
    {   //i是我们枚举的gcd 
        for (int j=i;j<=mx;j+=i)
            for (int k=sta[j];k;k=e[k].nxt)   //相同权值的加入树中
                add(e[k].x,e[k].y);
        mxlen=0;
        num++;
        for (int k=1;k<=tot;k++)
            if (p[link[k]]!=num) dfs(link[k]);
        for (int k=1;k<=tot;k++) st[link[k]]=0;
        //memset(st,0,sizeof(st));
        tot=0;
        ans[mxlen]=i;  //枚举的gcd 
    }
    for (int i=n-1;i>0;i--) ans[i]=max(ans[i],ans[i+1]);  //ans一定是不增的 
    for (int i=1;i<=n;i++) printf("%d\n",ans[i]);
    return 0;
}
<think>我们被要求提供关于Python中`os.walk`方法的使用指南。`os.walk`是一个用于目录遍历的常用方法,它可以遍历指定目录及其所有子目录,并返回每个目录下的文件夹列表文件列表。 ### 核心概念 `os.walk(top, topdown=True, onerror=None, followlinks=False)` - **top**: 要遍历的目录路径(字符串) - **topdown**: 遍历顺序(默认为True,即从顶层向子目录遍历;False则自底向上) - **onerror**: 错误处理函数(可选) - **followlinks**: 是否跟随符号链接(默认为False) ### 返回值 生成器,每次生成一个三元组`(root, dirs, files)`: - **root**: 当前正在遍历的目录路径(字符串) - **dirs**: root目录下的子目录名称列表(不包括`.``..`) - **files**: root目录下的非目录文件名称列表 ### 使用步骤 1. **导入os模块** 2. **调用os.walk()并循环处理结果** 3. **在循环中处理每个目录的文件夹文件** ### 基本示例 ```python import os # 指定要遍历的目录 start_dir = "/path/to/start" # 遍历目录树 for root, dirs, files in os.walk(start_dir): print(f"当前目录: {root}") print(f"包含子目录: {dirs}") print(f"包含文件: {files}") print("-" * 50) ``` ### 高级用法 #### 1. 控制遍历顺序 - **自上而下(topdown=True)**: 可以在循环中修改`dirs`列表来改变后续遍历为 ```python for root, dirs, files in os.walk(start_dir): # 忽略名为&#39;temp&#39;的目录(不遍历其子目录) if &#39;temp&#39; in dirs: dirs.remove(&#39;temp&#39;) # 修改dirs列表会影响后续遍历 ``` - **自下而上(topdown=False)**: 先遍历子目录,最后处理父目录 ```python for root, dirs, files in os.walk(start_dir, topdown=False): # 此时修改dirs列表不会影响遍历(因为子目录已处理) ``` #### 2. 错误处理 ```python def handle_error(error): print(f"遍历错误: {error}") for root, dirs, files in os.walk(start_dir, onerror=handle_error): # 正常处理 ``` #### 3. 跟随符号链接 ```python # 注意:跟随符号链接可能导致无限循环(如存在循环链接) for root, dirs, files in os.walk(start_dir, followlinks=True): # 处理 ``` #### 4. 搜索特定文件 ```python # 查找所有扩展名为.txt的文件 txt_files = [] for root, dirs, files in os.walk(start_dir): for file in files: if file.endswith(".txt"): txt_files.append(os.path.join(root, file)) ``` #### 5. 计算目录大小 ```python total_size = 0 for root, dirs, files in os.walk(start_dir): for file in files: file_path = os.path.join(root, file) try: total_size += os.path.getsize(file_path) except OSError: pass # 忽略无法访问的文件 ``` ### 性能与注意事项 1. **效率**:`os.walk()`在内部使用`os.scandir()`(Python 3.5+),效率较高[^1] 2. **隐藏文件**:返回结果包含隐藏文件目录(以`.`开头) 3. **权限问题**:遇到无权限目录会抛出异常,需用`try-except`或`onerror`处理 4. **路径拼接**:使用`os.path.join(root, name)`获取完整路径 ### 与替代方案对比 | 方法 | 递归 | 易用性 | 性能 | 功能完整性 | |---------------|------|--------|------|------------| | os.walk() | 是 | 高 | 高 | 高 | | os.scandir() | 否 | 中 | 极高 | 中 | | pathlib.Path()| 是 | 极高 | 中 | 高 | ```mermaid graph TD A[开始遍历] --> B[获取当前目录信息] B --> C{topdown?} C -->|True| D[先处理当前目录] D --> E[修改dirs?] E -->|是| F[更新后续遍历目录] E -->|否| G[遍历子目录] C -->|False| H[先遍历子目录] H --> I[最后处理当前目录] G --> J[继续下一目录] I --> J ``` > 注意:在Windows系统上,路径分隔符使用反斜杠`\`,而在Unix系统上使用正斜杠`/`。`os.walk()`返回的路径会使用操作系统对应的分隔符。 ### 常见问题解决 **Q1: 如何排除特定目录?** ```python exclude = [&#39;.git&#39;, &#39;node_modules&#39;] for root, dirs, files in os.walk(start_dir): # 从dirs中移除要排除的目录(阻止进入) dirs[:] = [d for d in dirs if d not in exclude] ``` **Q2: 如何限制遍历深度?** ```python max_depth = 3 for root, dirs, files in os.walk(start_dir): # 计算当前深度:从起点开始的路径分隔符数量差 depth = root[len(start_dir):].count(os.sep) if depth >= max_depth: del dirs[:] # 清空子目录列表,不再深入 ``` **Q3: 如何处理路径编码问题?** - 在Python 3中,所有路径均为字符串(UTF-8编码) - 遇到无法解码的文件名时,会返回bytes对象(罕见情况) ### 总结 `os.walk()`是Python目录遍历的核心工具,它通过生成器高效地遍历目录树,适合处理文件系统任务。其关键优势在于: 1. 简单直观的三元组结构 2. 支持深度控制目录过滤 3. 跨平台兼容性 在实际应用中,建议: - 结合`try-except`处理权限问题 - 避免在遍历过程中修改文件系统结构 - 对大目录使用`topdown=False`减少内存占用 §§相关问题§§ 1. 如何用`os.walk`实现文件搜索工具? 2. `os.walk`与`pathlib`模块在目录遍历上有何异同? 3. 遍历过程中如何实时显示进度? 4. 如何使用`os.walk`删除空目录? 5. `os.walk`在处理符号链接时有哪些注意事项?</think>### Python os.walk 方法使用指南 `os.walk()` 是 Python 中用于递归遍历目录结构的核心方法,通过生成器高效返回目录树信息。以下是详细使用指南: #### 1. 基本语法 ```python import os for root, dirs, files in os.walk(top_path, topdown=True, onerror=None, followlinks=False): # 处理逻辑 ``` 参数说明: - `top_path`:要遍历的根目录路径 - `topdown`:遍历顺序(默认True:父目录→子目录) - `onerror`:错误处理函数 - `followlinks`:是否跟随符号链接(默认False) #### 2. 返回值解析 每次迭代返回三元组: ```python (root, dirs, files) ``` - `root`:当前目录路径(字符串) - `dirs`:当前目录下的**子目录列表**(不含路径) - `files`:当前目录下的**文件列表**(不含路径) #### 3. 基础使用示例 ```python import os for root, dirs, files in os.walk("/projects"): print(f"目录: {root}") print(f"子文件夹: {dirs}") print(f"文件: {files}\n") ``` #### 4. 核心功能演示 **场景1:递归列出所有文件** ```python all_files = [] for root, _, files in os.walk("/data"): for file in files: full_path = os.path.join(root, file) # 拼接完整路径 all_files.append(full_path) ``` **场景2:过滤特定文件类型** ```python py_files = [] for root, _, files in os.walk("/src"): py_files.extend( os.path.join(root, f) for f in files if f.endswith(".py") ) ``` **场景3:控制遍历深度** ```python max_depth = 2 for root, dirs, files in os.walk("/docs"): # 计算当前深度 depth = root.count(os.sep) - start_depth if depth >= max_depth: dirs[:] = [] # 清空子目录列表,停止递归 ``` #### 5. 高级技巧 **动态修改遍历路径** ```python for root, dirs, files in os.walk("/tmp", topdown=True): if "skip_this" in dirs: dirs.remove("skip_this") # 阻止进入特定目录 ``` **错误处理** ```python def handle_error(err): print(f"访问错误: {err.filename}") for root, dirs, files in os.walk("/sys", onerror=handle_error): # 正常处理逻辑 ``` **符号链接处理** ```python # 警告:可能引发循环遍历 for root, dirs, files in os.walk("/var", followlinks=True): # 处理包含符号链接的目录 ``` #### 6. 性能优化建议 1. **惰性求值**:`os.walk()` 是生成器,适合大目录 ```python # 不推荐:list(os.walk())会立即加载所有数据 ``` 2. **提前终止**:使用 `break` 或修改 `dirs` 列表 3. **内存优化**:处理完立即释放变量 ```python for root, dirs, files in os.walk("/large_dir"): process_files(files) del dirs, files # 及时释放内存 ``` #### 7. 常见问题解决 **问题1:跳过无权限目录** ```python for root, dirs, files in os.walk("/"): try: os.listdir(root) # 测试目录访问权限 except PermissionError: dirs[:] = [] # 跳过当前目录的子目录 continue ``` **问题2:路径编码处理** ```python for root, dirs, files in os.walk(b"/binary_path"): # 字节路径 # 处理字节串路径 ``` #### 8. 与替代方案对比 | 方法 | 递归 | 易用性 | 性能 | 适用场景 | |--------------|------|--------|------|-----------------------| | `os.walk` | ✓ | 高 | 高 | 标准目录遍历 | | `os.scandir` | ✗ | 中 | 极高 | 非递归/单层访问 | | `pathlib` | ✓ | 极高 | 中 | 面向对象/现代代码 | > 在 Python 3.5+ 中,`os.walk()` 内部使用 `os.scandir()` 实现,性能较旧版提升 2-20 倍[^1]。 ```mermaid graph TD A[调用 os.walk] --> B{遍历开始} B --> C[获取当前目录信息] C --> D[处理文件] D --> E{存在子目录?} E -->|是| F[进入子目录] F --> C E -->|否| G[返回上级目录] G --> H{还有未处理目录?} H -->|是| C H -->|否| I[遍历结束] ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值