洛谷题单指南-线段树的进阶用法-Pathwalks
原题链接:https://www.luogu.com.cn/problem/CF960F
题意解读:按输入顺序从边中选出能首尾相连且权值递增的最多边数。
解题思路:
依然从最长上升子序列的模型出发,
对于输入的第i条边,用a[i],b[i],w[i]分别表示起点、终点、权值,
设f[i]表示第i条边结束的w的最长上升子序列长度,
则有f[i] = max(f[j]) +1,且需满足j < i, b[j] == a[i], w[j] < w[i]
似乎又是一个类似偏序的问题,第一维用来维护b,第二维用来维护w对应的最长上升子序列maxf
由于第一维每次只做相等判断,只需要用root[N]维护多个线段树的根节点,不需借助树状数组
第二维就是root[i]对应的权值线段树,节点值为w,维护信息为当前边的最长上升子序列maxf
只需要按输入顺序遍历所有边,
对于每条边a[i],b[i],w[i],在root[a[i]]中查询权值<w[i]的最大maxf,记为res,计算当前f[i] = res + 1
然后将root[b[i]]为根的线段树值为w[i]的maxf更新为f[i],不断递推即可求得所有f[i],记录最大值即可。
100分代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 100005;
struct Node
{
int L, R;
int maxf;
} tr[N * 20];
int root[N], idx;
int a[N], b[N], w[N], maxw;
int f[N]; //f[i]表示以第i条边结束的w的最长上升子序列长度
int n, m, ans;
//在根为u的线段树中查询值<v的最大的maxf
int query(int u, int l, int r, int v)
{
if(r < v) return tr[u].maxf;
else if(l >= v) return 0;
else
{
int mid = l + r >> 1;
return max(query(tr[u].L, l, mid, v), query(tr[u].R, mid + 1, r, v));
}
}
//将根为u的线段树值v的maxf更新为f,如果f更大的话
int update(int u, int l, int r, int v, int f)
{
if(!u) u = ++idx;
tr[u].maxf = max(tr[u].maxf, f);
if(l == r) return u;
int mid = l + r >> 1;
if(v <= mid) tr[u].L = update(tr[u].L, l, mid, v, f);
else tr[u].R = update(tr[u].R, mid + 1, r, v, f);
return u;
}
int main()
{
cin >> n >> m;
for(int i = 1; i <= m; i++)
{
cin >> a[i] >> b[i] >> w[i];
maxw = max(maxw, w[i]);
}
for(int i = 1; i <= m; i++)
{
f[i] = query(root[a[i]], 0, maxw, w[i]) + 1;
ans = max(ans, f[i]);
root[b[i]] = update(root[b[i]], 0, maxw, w[i], f[i]);
}
cout << ans;
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?