首页 技术 正文
技术 2022年11月11日
0 收藏 362 点赞 4,063 浏览 2423 个字

给定一棵树, 你可以在树的直径上确定一条长度不超过 \(S\) 的链, 使得树上离此链最长的点距离最小, 输出这个距离

P2491 数据范围为 P1099 的 \(1000\) 倍

Solution

首先两次 \(dfs\) 确定树的直径, 即第一次随意从某一点出发到达最远点记为 \(s\), 第二次从 \(s\) 出发到达最远点 \(t\) , 则 \(s-t\) 即为树的直径

现在我们得到了直径, 试想树上现在有一条链, 包含点 \(a_{1},a_{2}…a_{n}\), 树上到此链最长的点无非是以下三个的最大值:

  1. \(a_{1}\) 到直径首的长度
  2. \(a_{t}\) 到直径末的长度
  3. \(Max_{i = 1}^{t}d_{i}\), \(d_{i}\) 为点 \(i\) 在不经过直径能到达最远点的长度

通过树的性质可得: 链上最远点长度必然包括直径到最远点的长度(才能保证最优)

所以实际上我们只需要维护在直径上长度不超过 \(S\) 的链的 \(1, 2\) 两点, 与直径最长取最大值即可

贪心可得在保证链长 \(<=S\) 的情况下越长越优

所以维护两个指针 \(l, r\), 维护链上的左右端点

枚举每一个右端点同时保持链长 \(<= S\) ,缩短左端点更新答案即可

此题细节较多,看注释

Code(P2491)

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#include<vector>
#define LL long long
using namespace std;
int RD(){
int out = 0,flag = 1;char c = getchar();
while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
return flag * out;
}
const int maxn = 600019,INF = 1e9 + 19;
int head[maxn],nume = 1;
struct Node{
int v,dis,nxt;
}E[maxn << 3];
void add(int u,int v,int dis){
E[++nume].nxt = head[u];
E[nume].v = v;
E[nume].dis = dis;
head[u] = nume;
}
int num, S;
int s, t;
int pre[maxn], dis[maxn], disl[maxn], disr[maxn], disnxt[maxn];//前驱点,非路径距离,链上距离,邻接距离
vector<int>G;
bool vis[maxn];
struct Fa{int p, dis;};
Fa get_longest(int u, int F, int tim){//函数多用
Fa ret = (Fa){u, 0};int last = u, dn = 0;
for(int i = head[u];i;i = E[i].nxt){
int v = E[i].v;
if(v == F || vis[v])continue;
Fa ansv = get_longest(v, u, tim);
if(ansv.dis + E[i].dis > ret.dis){
last = v, dn = E[i].dis;
ret.dis = ansv.dis + E[i].dis;
ret.p = ansv.p;
}
}
if(tim == 1)pre[u] = last, disnxt[u] = dn;
return ret;
}
int ans = INF;
struct Que{
int index, val;
}Q[maxn];
int get_min(){
int now = s, add = 0;
while(pre[now] != now){
G.push_back(now);//入链
dis[now] = get_longest(now, -1, 0).dis;//处理非链上最长路径
add = max(add, dis[now]);
now = pre[now];
}
G.push_back(now);
dis[now] = get_longest(now, -1, 0).dis;//处理终点
add = max(add, dis[now]);
int tot = 0;
for(int i = G.size() - 1;i >= 1;i--){
now = G[i];
disr[now] = tot;
tot += disnxt[G[i - 1]];
}
disr[s] = tot;//处理链上最长距离的另一半
int l = 0, r = 0, len = 0;
ans = max(add, disr[G[r]]);
while(r < G.size()){
len += disnxt[G[r]];r++;
while(len > S)len -= disnxt[G[l]], l++;
//printf("l=%d r=%d\n", G[l], G[r]);
now = max(disr[G[r]], disl[G[l]]);
now = max(now, add);
ans = min(ans, now);
}
ans = max(ans, add);
return ans;
}
int main(){
num = RD();S = RD();
for(int i = 1;i <= num - 1;i++){
int u = RD(), v = RD(), dis = RD();
add(u, v, dis), add(v, u, dis);
}
s = get_longest(1, -1, 0).p, t = get_longest(s, -1, 1).p;
int i = s, tot = 0;
while(pre[i] != i)vis[i] = 1, disl[i] = tot, tot += disnxt[i], i = pre[i];//s到t
vis[t] = 1, disl[t] = tot;//标记直径上的点, 处理链上最长路径
printf("%d\n", get_min());
return 0;
//for(int i = 1;i <= num;i++)if(vis[i])printf("dis[%d]=%d\n", i, dis[i]);
}
相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,088
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,564
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,413
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,186
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,822
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,905