Live2D

[CTSC2017]网络 题解

link

Solution

可以证明的是,答案两个端点一定在直径上面。然后我们列出式子,拆开绝对值,直接二分,用单调栈维护,确定 \(a,b\) 范围,判断是否合法。

复杂度 \(\Theta(n\log n)\)

Code

#include <bits/stdc++.h>
using namespace std;

#define Int register int
#define int long long
#define MAXN 100005

template <typename T> void read (T &x){char c = getchar ();x = 0;int f = 1;while (c < '0' || c > '9') f = (c == '-' ? -1 : 1),c = getchar ();while (c >= '0' && c <= '9') x = x * 10 + c - '0',c = getchar ();x *= f;}
template <typename T,typename ... Args> void read (T &x,Args& ... args){read (x),read (args...);}
template <typename T> void write (T x){if (x < 0) x = -x,putchar ('-');if (x > 9) write (x / 10);putchar (x % 10 + '0');}
template <typename T> void chkmax (T &a,T b){a = max (a,b);}
template <typename T> void chkmin (T &a,T b){a = min (a,b);}

int n,L;

#define pii pair<int,int>
#define se second
#define fi first
vector <pii> g[MAXN];

bool vis[MAXN];
int N,root,dis[MAXN],pre[MAXN],len[MAXN],dit[MAXN];
void dfs (int u,int fa){
	if (dis[u] > dis[root]) root = u;
	for (pii it : g[u]) if (it.fi != fa && !vis[it.fi]) dis[it.fi] = dis[u] + it.se,pre[it.fi] = u,dfs (it.fi,u);
}

/*
若答案为(a,b),那么对于任意i,j,需要满足:
min(dit[i]+dit[j]+len[j]-len[i],dit[i]+dit[j]+|len[i]-len[a]|+|len[j]-len[b]|+L)<=S
考虑对于前者条件不符合的情况,判断后者,需要满足:
dit[i]+dit[j]+len[i]-len[a]+len[j]-len[b]+L<=S => 
dit[i]+dit[j]+len[i]+len[j]+L-S<=+len[a]+len[b]
dit[i]+dit[j]-len[i]+len[a]+len[j]-len[b]+L<=S => 
dit[i]+dit[j]-len[i]+len[j]+L-S<=-len[a]+len[b]
dit[i]+dit[j]+len[i]-len[a]-len[j]+len[b]+L<=S => 
dit[i]+dit[j]+len[i]-len[j]+L-S<=+len[a]-len[b]
dit[i]+dit[j]-len[i]+len[a]-len[j]+len[b]+L<=S => 
dit[i]+dit[j]-len[i]-len[j]+L-S<=-len[a]-len[b]
*/

#define inf 4e18
int sta[MAXN];
bool check (int S){//判断答案<=S的合法性
//	cout << S << endl; 
	int head = 1,tail = 0;
	int mxv0 = -inf,mxv1 = -inf,s00 = -inf,s01 = -inf,s10 = -inf,s11 = -inf;
	for (Int i = 1;i <= N;++ i){
		while (head <= tail && (len[i] + dit[i] + dit[sta[head]] - len[sta[head]]) > S)
			chkmax (mxv0,dit[sta[head]] + len[sta[head]]),
			chkmax (mxv1,dit[sta[head]] - len[sta[head]]),head ++;
		int res = dit[i] + L - S;
		chkmax (s11,len[i] + res + mxv0),chkmax (s01,-len[i] + res + mxv0),
		chkmax (s00,-len[i] + res + mxv1),chkmax (s10,len[i] + res + mxv1);
		while (head <= tail && dit[sta[tail]] - len[sta[tail]] < dit[i] - len[i]) tail --;
		sta[++ tail] = i;
	}
	int p01 = 1,p11 = N + 1,p10 = 0,p00 = N;
	for (Int i = 1;i <= N;++ i){
		while (p01 <= N && len[p01] - len[i] < s01) p01 ++;//[p01,N]合法 
		while (p11 >= 1 && len[p11 - 1] + len[i] >= s11) p11 --;//[p11,N]合法 
		while (p10 <= N && -len[p10 + 1] + len[i] >= s10) p10 ++;//[1,p10]合法 
		while (p00 >= 1 && -len[p00] - len[i] < s00) p00 --;//[1,p00]合法 
		if (max (p01,p11) <= min (p10,p00)) return 1;
	}
	return 0;
}

signed main(){
//	freopen ("1.in","r",stdin);
	while (~scanf ("%lld%lld",&n,&L) && n && L){
		for (Int i = 1;i <= n;++ i) g[i].clear (),vis[i] = 0;N = 0;
		for (Int i = 2,u,v,w;i <= n;++ i) read (u,v,w),g[u].push_back ({v,w}),g[v].push_back ({u,w});
		dis[root] = pre[root] = 0,root = 1,dfs (1,0),dis[root] = 0,pre[root] = 0,dfs (root,0);int rt = root,mxv = dis[rt];
		for (Int u = rt;u;u = pre[u]) vis[u] = 1;
		for (Int u = rt;u;u = pre[u]) len[++ N] = mxv - dis[u],root = 0,dis[u] = 0,dfs (u,0),dit[N] = dis[root];
		int l = 0,r = inf,ans = 0;
		while (l <= r){
			int mid = l + r >> 1;
			if (check (mid)) ans = mid,r = mid - 1;
			else l = mid + 1;
		}
		write (ans),putchar ('\n');
	}
	return 0;
}
posted @ 2022-02-28 22:31  Dark_Romance  阅读(103)  评论(0编辑  收藏  举报