【ssl 2570】 【树形DP】 【单调队列】 幸福的道路

该博客主要讲述了如何使用树形动态规划和单调队列解决SSL 2570问题,旨在求解以每个节点为起点的最长路径,并确保最大差值不超过给定限制m。博主分享了从2020年至2022年未解出问题的困扰,并提供了解题思路和代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【ssl 2570】 【树形DP】 【单调队列】 幸福的道路

题目

在这里插入图片描述

解题思路

我没过。。。从2020到2022的悲剧,有人看出来的话踢踢我
先用树形DP求出以每个点为起点的最长路径
因为最大差值不能超过m
用单调队列维护区间最小值和最大值
如果超过了,就将日期早的往后


代码

#include<iostream>
#include<cstdio>
using namespace std;
struct lzf{
	int to,q,nxt;
}f[2000010];
struct node{
	int j,id;
}d[1000100],d2[1000100];
int n,m,x,y,t,s=1,h=1,z1,z2,ans;
int head[1000010],q1[1000010],q2[1000010];
void add(int x,int y,int q)
{
	 f[++t].to=y;
	 f[t].q=q;
	 f[t].nxt=head[x];
	 head[x]=t;
}
void dp(int fa,int x)  //求往下的最长链和次长链 
{ 
	 for (int i=head[x];i;i=f[i].nxt)
	 {
	 	 dp(x,f[i].to);
	 	 if (d2[f[i].to].j+f[i].q>d2[x].j)
	 	 {
	 	 	d[x]=d2[x];
	 	 	d2[x]=(node){d2[f[i].to].j+f[i].q,f[i].to};
		 }
		 else if (d[f[i].to].j+f[i].q>d[x].j) d[x]=(node){d2[f[i].to].j+f[i].q,f[i].to};
	 }
}
void dfs(int fa,int x,int w)  //用向上走更新最长链和次长链 
{
	 int len;
	 if (x==d2[fa].id) len=d[fa].j+w;
	    else len=d2[fa].j+w;
	 if (len>d2[x].j) d[x]=d2[x],d2[x]=(node){len,fa};
	    else if (len>d[x].j) d[x]=(node){len,fa};
	 for (int i=head[x];i;i=f[i].nxt)
	     if (f[i].to!=fa) dfs(x,f[i].to,f[i].q);
}
int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1;i<n;i++)
	{
		scanf("%d%d",&x,&y); 
		add(x,i+1,y);
	}
	dp(0,1);
	dfs(0,1,0); 
	x=1;
	for (int i=1;i<=n;i++)
	{
		while (h<=z1&&d2[q1[z1]].j<=d2[i].j) z1--;  //维护区间最大 
		while (s<=z2&&d2[q2[z2]].j>=d2[i].j) z2--;  //维护区间最小 
		q1[++z1]=i,q2[++z2]=i; 
        while (d2[q1[h]].j-d2[q2[s]].j>m)  //维护差值不超过m
        {
        	  if (q1[h]<q2[s]) x=q1[h]+1,h++;
        	     else x=q2[s]+1,s++;
		}
		ans=max(ans,i-x+1); 
	}
	printf("%d",ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值