#单调队列,树的直径#bzoj 1999 洛谷 1099 树网的核

洛谷链接
bzoj链接


分析

首先两遍bfs求出树的直径,预处理对于每个点的最大偏心距,枚举直径上的左端点 l l l,那么对于右端点 r r r,答案就是 m a x ( m a x ( m x i i ∈ [ l ∼ r ] ) , m a x ( d i s [ r ] − d i s [ s ] , d i s [ t ] − d i s [ l ] ) ) max(max(mx_i i\in[l\sim r]),max(dis[r]-dis[s],dis[t]-dis[l])) max(max(mxii[lr]),max(dis[r]dis[s],dis[t]dis[l])),时间复杂度 O ( n 3 ) O(n^3) O(n3)
不对啊,bzoj怎么过,
首先, r r r应该递增会让答案更优,所以说用双指针,so O ( n 2 ) O(n^2) O(n2)
不对呀,貌似还是TLE
要用单调队列维护最大偏心距 O ( n ) O(n) O(n)


代码

#include <cstdio>
#include <cstring>
#include <cctype>
#include <queue>
#define rr register
using namespace std;
struct node{int y,w,next;}e[1000001]; bool v[500001]; int n,m,k=1,s,t;
int ans=2147483647,dis[500001],pre[500001],ls[500001],mx[500001],q[500001];
inline signed iut(){
    rr int ans=0; rr char c=getchar();
    while (!isdigit(c)) c=getchar();
    while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    return ans;
}
inline signed bfs(int s){
	rr queue<int>q; q.push(s); pre[s]=0;
	memset(dis,0,sizeof(dis));
	while (q.size()){
		rr int x=q.front(); q.pop();
		for (rr int i=ls[x];i;i=e[i].next)
		if (!dis[e[i].y]&&e[i].y!=s){
			dis[e[i].y]=dis[x]+e[i].w;
			q.push(e[i].y); pre[e[i].y]=x;
		}
	}
	rr int t=1;
	for (rr int i=1;i<=n;++i)
	    t=dis[i]>dis[t]?i:t;
	return t;
}
inline void bfs2(int s){
	rr queue<pair<int,int> >q; q.push(make_pair(s,0));
	while (q.size()){
		rr int x=q.front().first,now=q.front().second; q.pop();
		for (rr int i=ls[x];i;i=e[i].next)
		if (!v[e[i].y]){
			v[e[i].y]=1; rr int t=now+e[i].w;
			mx[s]=mx[s]>t?mx[s]:t; q.push(make_pair(e[i].y,t));
		}
	}
} 
signed main(){
	n=iut(); m=iut();
	for (rr int i=1;i<n;++i){
		rr int x=iut(),y=iut(),w=iut();
		e[++k]=(node){y,w,ls[x]}; ls[x]=k;
		e[++k]=(node){x,w,ls[y]}; ls[y]=k;
	}
	s=bfs(1); t=bfs(s);
	for (rr int i=t;i;i=pre[i]) v[i]=1;
	for (rr int i=t;i;i=pre[i]) bfs2(i);
	rr int r=t,head=1,tail=1; q[1]=t;
	for (rr int l=t;l;l=pre[l]){
		while (pre[r]&&dis[l]-dis[pre[r]]<=m){
			r=pre[r];
			while (head<=tail&&mx[q[tail]]<=mx[r]) --tail; q[++tail]=r;
			rr int now=dis[t]-dis[l]<mx[q[head]]?mx[q[head]]:dis[t]-dis[l];
			rr int tt=dis[r]-dis[s]<now?now:dis[r]-dis[s]; ans=ans<tt?ans:tt;
		}
		if (q[head]==l) ++head;
	}
    return !printf("%d",ans);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值