#单调队列,树形dp#ssl 2443 2570 bzoj 2500 幸福的道路

题目

一棵树,点的权值等于从该点走的最长的一条路,问最长的区间 [ l . . . r ] [l...r] [l...r]最大点权与最小点权之差不超过 m m m


分析

首先先要求点权,也就是求树最长链,可以用树形dp解决,求出最长路+次长路,然后找区间必须得用 O ( n ) O(n) O(n)的时间解决(理论上 O ( n l o g n ) O(nlogn) O(nlogn)是会超时的),所以说可以用单调队列解决,然后就没有什么了


代码

#include <cstdio>
#define N 1000001
struct node{int y,w,next;}e[N]; 
struct rec{int w,num;}d1[N],d2[N];
int ls[N],n,m,q1[N],q2[N];
int in(){
	int ans=0; char c=getchar();
	while (c<48||c>57) c=getchar();
	while (c>47&&c<58) ans=ans*10+c-48,c=getchar();
	return ans;
}
int max(int a,int b){return (a>b)?a:b;}
void dp(int x,int fa){
	for (register int i=ls[x];i;i=e[i].next){
		dp(e[i].y,x);
		if (d1[e[i].y].w+e[i].w>d1[x].w)//次长路=当前最长路,当前最长路=更长路
			d2[x]=d1[x],d1[x]=(rec){d1[e[i].y].w+e[i].w,e[i].y};
		else if (d1[e[i].y].w+e[i].w>d2[x].w)
		    d2[x]=(rec){d1[e[i].y].w+e[i].w,e[i].y};//次长路=更长路
	}
}
void dfs(int x,int fa,int w){
	int len=(d1[fa].num==x)?d2[fa].w+w:d1[fa].w+w;//最长路+次长路
	if (len>d1[x].w) d2[x]=d1[x],d1[x]=(rec){len,fa};//the same
	else if (len>d2[x].w) d2[x]=(rec){len,fa};
	for (int i=ls[x];i;i=e[i].next)
		dfs(e[i].y,x,e[i].w);
}
int main(){
    n=in(); m=in(); 
	int ans=1,head1=1,tail1=0,head2=1,tail2=0;
    for (register int i=2;i<=n;i++){
    	int x=in();
    	e[i-1]=(node){i,in(),ls[x]},ls[x]=i-1;
    } 
    dp(1,0); dfs(1,0,0); int num=1;
    for (register int i=1;i<=n;i++){
    	while (head1<=tail1&&d1[q1[tail1]].w>=d1[i].w) tail1--; q1[++tail1]=i; //更优的答案
    	while (head2<=tail2&&d1[q2[tail2]].w<=d1[i].w) tail2--; q2[++tail2]=i;//the same
    	while (d1[q2[head2]].w>d1[q1[head1]].w+m){//在区间外
    		if (q1[head1]<q2[head2]) num=q1[head1++]+1;//num表示当前满足区间的在哪里
    		else num=q2[head2++]+1;
    	}
    	ans=max(ans,i-num+1);//求答案
    }
    return !printf("%d",ans);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值