树上滑窗

回溯实现,dfs遍历中记录维护

树上滑窗算法,++在树的 DFS 遍历中,维护"窗口内不重复的颜色最近出现深度",动态调整窗口起点,在一次遍历中++高效求出满足"同色不重复"约束的最长路径

树上滑窗·五步法(同色不重复最长路径)

  1. 建树:把边转成无向邻接表,存节点与边权

  2. 入栈:DFS 进入节点时,++记录颜色上一次出现位置,更新窗口左边界++

  3. 算答案:用++前缀和算当前窗口路径长度++,更新最优解

  4. 递归:遍历子节点,维护路径和并回溯

  5. ++回溯:恢复颜色位置与路径和,保证不影响其他分支++

模板

"路径上元素不重复/满足某种窗口约束"的问题,可直接套用:

#include <bits/stdc++.h>

using namespace std;

using ll = long long;

pair<ll, int> treeSlidingWindow(

int n,

const vector<vector<pair<int, int>>>& g, // 邻接表: {to, weight}

const vector<int>& color // 每个节点的"颜色"/值

) {

pair<ll, int> best = {-1, 0}; // {max_length, start_depth}

vector<ll> dis = {0}; // 路径前缀和

unordered_map<int, int> last; // 颜色 -> 上一次出现的深度 + 1

function<void(int, int, int)> dfs = \&(int u, int fa, int top_depth) {

int c = coloru;

int old = lastc;

top_depth = max(top_depth, old); // 窗口左边界更新

// 更新最优解:长度 = 当前前缀和 - 窗口起点前缀和

ll len = dis.back() - distop_depth;

if (len > best.first || (len == best.first && top_depth < best.second)) {

best = {len, top_depth};

}

lastc = dis.size(); // 记录当前颜色位置

for (auto& v, w : gu) {

if (v != fa) {

dis.push_back(dis.back() + w);

dfs(v, u, top_depth);

dis.pop_back();

}

}

lastc = old; // 回溯恢复

};

dfs(0, -1, 0);

return best;

}

// 示例主函数

int main() {

int n;

cin >> n;

vector<int> color(n);

for (int i = 0; i < n; ++i) cin >> colori;

vector<vector<pair<int, int>>> g(n);

for (int i = 0; i < n - 1; ++i) {

int x, y, w;

cin >> x >> y >> w;

gx.emplace_back(y, w);

gy.emplace_back(x, w);

}

++auto max_len, start_depth = treeSlidingWindow(n, g, color);++

cout << max_len << " " << start_depth << endl;

return 0;

}

说明

  1. 核心思想:在 DFS 遍历树时,用 ++last 哈希表记录每种颜色上一次出现的深度++,动态调整窗口左边界 top_depth ,保证窗口内颜色不重复。

  2. 前缀和 dis :记录从根到当前节点的路径和,用于快速计算窗口内路径长度。

  3. 时间复杂度:每个节点访问一次,哈希表操作平均 O(1),整体 O(n)。

  4. 可修改点:

  • 若约束不是"同色不重复",可修改 last 的更新逻辑。

  • 若需要返回具体路径,可在 DFS 中额外维护路径栈

lc3425

dfs 遍历树,++维护颜色最近出现深度和前缀和数组++

在 O(n) 时间内找到一条满足"同色不重复"的最长路径,并返回其长度与起点深度

这道题综合挺强的,有树,滑窗,前缀和,回溯

这些都想到了还是超时,还需要额外维护当前值上一次出现的深度来加快滑窗左端的移动速度...

class Solution {

public:

vector<int> longestSpecialPath(vector<vector<int>>& edges, vector<int>& nums) {

vector<vector<pair<int, int>>> g(nums.size());

for (auto& e : edges) {

int x = e0, y = e1, w = e2;

gx.emplace_back(y, w);

gy.emplace_back(x, w);

}

pair<int, int> ans = {-1, 0};

vector<int> dis = {0};

unordered_map<int, int> last_depth;

// 颜色 -> 该颜色最近一次出现的深度 +1,注意这里已经 +1 了

auto dfs = \&(this auto&& dfs, int x, int fa, int top_depth) -> void

{

int color = numsx;

int old_depth = last_depthcolor;

top_depth = max(top_depth, old_depth);

// 把 dis.size() - top_depth 取反,这样 max 算的是最小值

ans = max(ans, pair(dis.back() - distop_depth, top_depth - (int) dis.size()));

last_depthcolor = dis.size();

for (auto& y, w : gx) {

++if (y != fa) { // 避免访问父节点++

dis.push_back(dis.back() + w);

dfs(y, x, top_depth);

++dis.pop_back(); // 恢复现场++

}

}

++last_depthcolor = old_depth; // 恢复现场++

};

dfs(0, -1, 0);

return {ans.first, -ans.second};

}

};

lc3486

class Solution {

vector<int> nums;

vector<vector<pair<int, int>>> g;

pair<int, int> ans = {-1, 0};

vector<int> dis = {0};

unordered_map<int, int> last_depth;

// 颜色 -> 该颜色最近一次出现的深度 +1,注意这里已经 +1 了

// 对于本题,dfs 写外面效率更高(可能是 unordered_map 导致)

void dfs(int x, int fa, int top_depth, int last1) {

int color = numsx;

int last2 = last_depthcolor;

++top_depth = max(top_depth, min(last1, last2)); // 相较 3425 题,维护窗口左端点的逻辑变了++

ans = max(ans, pair(dis.back() - distop_depth, top_depth - (int) dis.size()));

last_depthcolor = dis.size();

for (auto& y, w : gx) {

if (y != fa) {

dis.push_back(dis.back() + w);

++dfs(y, x, top_depth, max(last1, last2)); // 相较 3425 题,额外维护 last1++

dis.pop_back();

}

}

last_depthcolor = last2;

}

public:

vector<int> longestSpecialPath(vector<vector<int>>& edges, vector<int>& nums) {

g.resize(nums.size());

for (auto& e : edges) {

int x = e0, y = e1, w = e2;

gx.emplace_back(y, w);

gy.emplace_back(x, w);

}

this->nums = nums;

dfs(0, -1, 0, 0);

return {ans.first, -ans.second};

}

};

相关推荐
mifengxing18 小时前
LeetCode热题100——字母异位词分组
java·算法·leetcode·职场和发展·哈希表·hot100
Billlly19 小时前
莫比乌斯反演学习笔记
算法
stolentime20 小时前
CF2066D1 Club of Young Aircraft Builders (easy version)题解
c++·算法·动态规划·组合数学
Dillon Dong20 小时前
【风电控制】高低穿现场失败的原因分析——算法简单但工程复杂
算法·变流器·风电控制·dfig
小欣加油20 小时前
leetcode41 缺失的第一个正数
数据结构·c++·算法·leetcode
I Promise3420 小时前
智驾APA_HPA可行驶区域检测算法工程师面试问题整理可参考
算法·面试·职场和发展
智者知已应修善业20 小时前
【51单片机按键控制1分钟正计时倒计时暂停复位】2024-1-2
c++·经验分享·笔记·算法·51单片机
weixin_4684668520 小时前
UNet 模型结构从零搭建与实战解析
人工智能·深度学习·算法·机器学习·ai·unet
Useasy_JIJIANYUN21 小时前
合作快讯:极简云呼叫中心(Useasy)正式上架Zoho全球应用市场!
算法
isyoungboy21 小时前
Delaunay 拓扑图割法一种特征抽稀算法
算法