树上滑窗

回溯实现,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};

}

};

相关推荐
大明者省4 小时前
WSL2 Ubuntu22.04 GPU训练环境配置指南
人工智能·算法·计算机视觉
白狐_7986 小时前
408数据结构第8章:排序②——性质对比秒杀、场景选择与外部排序
java·数据结构·算法
zander2586 小时前
LeetCode 84:柱状图中的最大矩形——单调栈如何确定左右边界
java·数据结构·算法
Shell运维手记7 小时前
Linux 常用基础命令学习笔记
linux·运维·笔记·学习·算法·github
杨航 AI7 小时前
O(n log n):线性对数原理拆解 这个是排序算法的黄金复杂度之一。
算法·排序算法
船厂电气自动化ai大模型8 小时前
AI大模型与数学 第32课 函数凹凸性与二阶导数:拐点求解、凹凸区间计算(10道二阶导数计算题)
数据结构·人工智能·python·深度学习·算法
旖旎夜光8 小时前
LeetCode 3:无重复字符的最长子串(滑动窗口) —— 题解
数据结构·c++·算法·leetcode·滑动窗口
叠层归一研究院9 小时前
AGI 系统(十一):二阶网络 — 二阶递归 × 多主体 (元符号网络)
开发语言·人工智能·算法·php·agi
zlinear数据采集卡9 小时前
D223的PWM电机控制:6路独立脉冲+加减速算法深度解析
arm开发·stm32·嵌入式硬件·算法·fpga开发·架构
杨石兴10 小时前
31、玩具MoM:用2x2矩阵串起全套流程
人工智能·算法·矩阵·电磁学