嘟嘟嘟

首先求树的直径两次bfs即可,实际上bfs就是最短路,因为树上路径是唯一的,所以用任何一种遍历方法都行(spfa和dijkstra当然也可以)。

可以证明,只要求出任意一条直径就行了,为什么呢?考虑一下,如果我们在直径上选了一段,那么最远偏心距可肯定是到直径两端的最大值,和直径外的点无关,只和直径的长度有关。

于是我们求完了直径。然后在直径上搞一搞:很容易想到,如果当前选了一段长度为a,他还可以延伸为b,且a < b < s,那么b的答案一定比a优。因此我们建立一个双指针L,R,代表当前选取的一段的左右端点,当L一定时,R要尽量远,如果超出了s,L指针就向前挪一个节点。其中dis数组就充当了前缀和数组的作用,然后每一次都尝试用max(dis[L], dis[end] - dis[R])更新答案,时间复杂度为O(n)。

需要注意的是,因为我们存路径都是反向存的,因此上面实际上应该是max(dis[R], dis[end] - dis[L]),而且跳的时候不是L++,R++,而是L = pre[L], R = pre[R].

别忘了还有一种情况:就是直径长度小于s,此时的答案应该是不在直径上的点到直径的最大值,只要对于直径上每一个节点向外dfs找就行,因为每一个节点只会遍历一次,所以时间复杂度还是O(n)。

  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cmath>
  4 #include<algorithm>
  5 #include<cstring>
  6 #include<cstdlib>
  7 #include<cctype>
  8 #include<vector>
  9 #include<stack>
 10 #include<queue>
 11 using namespace std;
 12 #define enter puts("")
 13 #define space putchar(' ')
 14 #define Mem(a) memset(a, 0, sizeof(a))
 15 #define rg register
 16 typedef long long ll;
 17 typedef double db;
 18 const int INF = 0x3f3f3f3f;
 19 const db eps = 1e-8;
 20 const int maxn = 5e5 + 5;
 21 inline ll read()
 22 {
 23     ll ans = 0;
 24     char ch = getchar(), last = ' ';
 25     while(!isdigit(ch)) {last = ch; ch = getchar();}
 26     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
 27     if(last == '-') ans = -ans;
 28     return ans;
 29 }
 30 inline void write(ll x)
 31 {
 32     if(x < 0) x = -x, putchar('-');
 33     if(x >= 10) write(x / 10);
 34     putchar(x % 10 + '0');
 35 }
 36
 37 int n, s;
 38 vector<int> v[maxn], c[maxn];
 39
 40 bool vis[maxn];
 41 int dis[maxn], pre[maxn], w[maxn];
 42 int bfs(int s)
 43 {
 44     Mem(vis); Mem(pre); Mem(w); Mem(dis);
 45     queue<int> q; q.push(s);
 46     vis[s] = 1;
 47     dis[s] = 0;
 48     while(!q.empty())
 49     {
 50         int now = q.front(); q.pop();
 51         for(int i = 0; i < (int)v[now].size(); ++i)
 52         {
 53             if(!vis[v[now][i]])
 54             {
 55                 vis[v[now][i]] = 1;
 56                 dis[v[now][i]] = dis[now] + c[now][i];
 57                 pre[v[now][i]] = now;
 58                 w[v[now][i]] = c[now][i];
 59                 q.push(v[now][i]);
 60             }
 61         }
 62     }
 63     int Max = -1, pos;
 64     for(int i = 1; i <= n; ++i) if(dis[i] > Max) Max = dis[i], pos = i;
 65     return pos;
 66 }
 67
 68 int ans = INF;
 69
 70 int dfs(int now, int x)
 71 {
 72     int ret = -1;
 73     for(int i = 0; i < (int)v[now].size(); ++i)
 74     {
 75         if(!vis[v[now][i]])
 76         {
 77             vis[v[now][i]] = 1;
 78             ret = max(ret, dfs(v[now][i], x + c[now][i]));
 79         }
 80     }
 81     return max(ret, x);
 82 }
 83 void solve(int b, int a)
 84 {
 85     Mem(vis);
 86     ans = -1;
 87     for(int i = b; i; i = pre[i]) {vis[pre[i]] = vis[i] = 1; ans = max(ans, dfs(i, 0));}
 88     write(ans); enter;
 89 }
 90
 91 int main()
 92 {
 93     n = read(); s = read();
 94     for(int i = 1; i < n; ++i)
 95     {
 96         int x = read(), y = read(), co = read();
 97         v[x].push_back(y); c[x].push_back(co);
 98         v[y].push_back(x); c[y].push_back(co);
 99     }
100     int a = bfs(1);
101     int b = bfs(a);
102     if(s >= dis[b]) {solve(b, a); return 0;}
103     int L = b, R = b;
104     for(int i = b; i; i = pre[i])
105     {
106         while(L != R && dis[L] - dis[R] + w[i] > s) L = pre[L];
107         if(dis[L] - dis[R] + w[i] > s) L = pre[i];
108         R = pre[i];
109         ans = min(ans, max(dis[R], dis[b] - dis[L]));
110     }
111     write(ans); enter;
112     return 0;
113 }

View Code

转载于:https://www.cnblogs.com/mrclr/p/9617934.html

[Noip2007]Core树网的核相关推荐

  1. bzoj 1999: [Noip2007]Core树网的核【树的直径+单调队列】

    我要懒死了,所以依然是lyd的课件截图 注意是min{max(max(d[uk]),dis(u1,ui),dis(uj,un))},每次都从这三个的max里取min #include<iostr ...

  2. [NOIP2007] 提高组 洛谷P1099 树网的核

    题目描述 设T=(V, E, W) 是一个无圈且连通的无向图(也称为无根树),每条边到有正整数的权,我们称T为树网(treebetwork),其中V,E分别表示结点与边的集合,W表示各边长度的集合,并 ...

  3. NOIP2007 树网的核 [BZOJ2282][Sdoi2011]消防

    NOIP2007 树网的核 树的直径的最长性是一个很有用的概念,可能对一些题都帮助. 树的直径 给定一棵树,树中每条边都有一个权值,树中两点之间的距离定义为连接两点的路径边权之和.树中最远的两个节点之 ...

  4. 树网的核 Vijos1362 NOIP2007 树结构 直径 暴搜

    题面在最下方. 树结构的题做多了就会发现,本题所谓的树网的核(一段偏心距ECC最小的路径)一定是在树的直径上的. 我刚开始做的时候没想到这个,然后写了三个dfs讨论每条直径 Orz 其实只要认识到了这 ...

  5. [O(N)的我不会]树网的核

    [题目描述] 设T=(V, E, W) 是一个无圈且连通的无向图(也称为无根树),每条边带有正整数的权,我们称T为树网(treenetwork),其中V, E分别表示结点与边的集合,W表示各边长度的集 ...

  6. 树网的核(codevs 1167)

    题目描述 Description [问题描述] 设 T=(V, E, W) 是一个无圈且连通的无向图(也称为无根树),每条边带有正整数的权,我 们称T 为树网(treenetwork),其中V, E分 ...

  7. VIJOS 1362 树网的核

    描述 设T=(V, E, W) 是一个无圈且连通的无向图(也称为无根树),每条边到有正整数的权,我们称T为树网(treebetwork),其中V,E分别表示结点与边的集合,W表示各边长度的集合,并设T ...

  8. NOIP2007 树网的核

    传送门 最近搞一搞树型结构--毕竟自己树的知识学的太垃圾了. 首先这道题非常明显要求树的直径.树的直径有好多好多种求法,这里我选择了一位dalao的非常简洁的dfs的方法.先看一下代码. void d ...

  9. 2017.3.21 树网的核 思考记录

    把这个noip的题搞出来了.. 不是很难,而且我的要求也比较高(虽然以前看到这种题都是直接看题解,因为太复杂不会) 虽然搞出来在luogu 的noip数据 A了,但bzoj还是T了.理论上应该是O(n ...

  10. code1167 树网的核

    floyd+枚举 看点: 1.floyd同时用数组p记录转移节点k,这样知道线段的端点u v就可以得到整条线段 2.任意一点c到线段a b的距离=(d[a][c]+d[c][b]-d[a][b])/2 ...

最新文章

  1. jbpm知识点——tasknode
  2. 会说话的狗狗本电脑版_会说话的电脑有点酷!惠普星14帮你解锁“偷懒”新姿势_惠普 星 14 2020(i5 1135G7/16GB/512GB/MX450)_笔记本新闻...
  3. 一致性哈希算法及其在分布式系统中的应用
  4. 分享 - Social.framework
  5. python判断计算机是否有网络连接
  6. 设计模式(一)--单一职责模式(衡量接口或类设计)
  7. html输入参数,传递输入参数,通过Html.ActionLink
  8. alien rpm deb,ubuntu下安装jdk过程及遇到的问题
  9. 经济学人:数据经济虽好,可是仍需补钙
  10. c#使用word、excel、pdf ——转
  11. 杀毒软件可以查杀已知的计算机病毒,杀毒软件可以查杀( )。
  12. 纯HTML标签详解(摘自阿里西西)
  13. 2015 年度新增开源软件排名TOP100
  14. 电驴emule使用教程
  15. mysql 语法大全
  16. 轻松创建天龙八部的场景
  17. CSS3实现图片翻转效果
  18. 解决 Windows系统 快捷方式 图标 变成 白色方块
  19. c语言:模拟用户密码登录
  20. Android 修改SIM卡默认VOLTE值

热门文章

  1. 5.2自动扫描及装配数据
  2. 【渝粤教育】国家开放大学2018年春季 0032-22T农业经济学 参考试题
  3. 【渝粤教育】广东开放大学 演绎娱乐经验管理 形成性考核 (49)
  4. ubuntu16.04 下ROS操作系统学习笔记(一)ROS-kinetic安装
  5. freeswitch 一些坑
  6. 慢慢人生路,学点Jakarta基础-集合类
  7. 快捷添加请求头的方法
  8. Unity编辑器扩展之RequireComponent等详解
  9. [转]Mathtype中批量修改公式的字体和大小
  10. 【iCore4 双核心板_FPGA】例程一:GPIO输出实验——点亮LED