题面

Bzoj

洛谷

题解

首先把最短路径树建出来(用\(Dijkstra\),没试过\(SPFA\)\(\leftarrow\)它死了),然后问题就变成了一个关于深度的问题,可以用长链剖分做,所以我们用点分治来做(滑稽)。

有一点要说,这一题数据比较水,如果不用字典序的话,也可以过。如何建立字典序呢?其实我们从\(1\)号节点开始遍历路径树(不是最短路径树),令一个点的第一关键字是点权,如果点权相等就按照编号大小为第二关键字,维护一个二元组就好了。

点分治时记两个数组\(S[i]\)和\(num[i]\),表示经过\(i\)个点的路径最大是多少以及在这个情况下有多少条路径。

之前找重心调了好久。

#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <iostream>
using std::pair; using std::sort;
using std::priority_queue;
using std::vector; using std::greater;
typedef long long ll;
typedef pair<int, int> pii;template<typename T>
void read(T &x) {int flag = 1; x = 0; char ch = getchar();while(ch < '0' || ch > '9') { if(ch == '-') flag = -flag; ch = getchar(); }while(ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); x *= flag;
}const int N = 3e4 + 10, Inf = 1 << 30;
int n, m, k, from[N], dist[N], MX, tot;
int cnt, to[N << 1], nxt[N << 1], dis[N << 1];
bool vis[N];
vector<pii> G[N]; priority_queue< pii, vector<pii>, greater<pii> > q;
void addEdge(int u, int v, int w) {to[++cnt] = v, nxt[cnt] = from[u], dis[cnt] = w, from[u] = cnt;
}void dijk(int s) {memset(dist, 0x7777777f, sizeof dist);dist[s] = 0, q.push((pii){0, s});while(q.size()) {int u = q.top().second; q.pop();if(vis[u]) continue; vis[u] = true;for(int i = 0; i < G[u].size(); ++i) {int v = G[u][i].first, w = G[u][i].second + dist[u];if(dist[v] > w) dist[v] = w, q.push((pii){dist[v], v});}}
}void init(int u) {vis[u] = 1;for(int i = 0; i < G[u].size(); ++i) {int v = G[u][i].first, w = G[u][i].second;if(vis[v] || w + dist[u] != dist[v]) continue;addEdge(u, v, w), addEdge(v, u, w), init(v);}
}int Size, tmp, p, siz[N], maxnow, S[N], num[N];
inline void upt(int &a, int b) { if(a < b) a = b; }void getrt(int u, int f) { int max_part = 0; siz[u] = 1;for(int i = from[u]; i; i = nxt[i]) {int v = to[i]; if(vis[v] || v == f) continue;getrt(v, u); siz[u] += siz[v];upt(max_part, siz[v]);} upt(max_part, Size - siz[u]);if(max_part < tmp) p = u, tmp = max_part;
}void calc(int u, int f, int now) {upt(maxnow, now);if(now == k - 1) {if(dist[u] == MX) ++tot;else if(dist[u] > MX) MX = dist[u], tot = 1;return ;}int nowans = -1;if(S[k - 1 - now] != -1) nowans = dist[u] + S[k - 1 - now];if(nowans == MX) tot += num[k - 1 - now];else if(nowans > MX) MX = nowans, tot = num[k - 1 - now];for(int i = from[u]; i; i = nxt[i]) {int v = to[i]; if(vis[v] || v == f) continue;dist[v] = dist[u] + dis[i], calc(v, u, now + 1);}
}void update(int u, int f, int now) {if(now == k - 1) return ;if(S[now] == dist[u]) ++num[now];else upt(S[now], dist[u]), num[now] = 1;for(int i = from[u]; i; i = nxt[i]) {int v = to[i]; if(vis[v] || v == f) continue;update(v, u, now + 1);}
}void doit(int x) {p = 0, tmp = Inf, getrt(x, 0), vis[p] = 1, maxnow = 0;for(int i = from[p]; i; i = nxt[i]) {int v = to[i]; if(vis[v]) continue;dist[v] = dis[i], calc(v, p, 1), update(v, p, 1);}for(int i = 1; i <= maxnow; ++i) S[i] = -1, num[i] = 0;for(int i = from[p]; i; i = nxt[i]) {int v = to[i]; if(vis[v]) continue;Size = siz[v], doit(v);}
}int main () {read(n), read(m), read(k);for(int i = 1, u, v, w; i <= m; ++i) {read(u), read(v), read(w);G[u].push_back((pii){v, w});G[v].push_back((pii){u, w});}for(int i = 1; i <= n; ++i) sort(G[i].begin(), G[i].end());dijk(1), memset(vis, 0, sizeof vis), init(1);Size = n, memset(vis, 0, sizeof vis);memset(dist, 0, sizeof dist), doit(1);printf("%d %d\n", MX, tot);return 0;
} 

转载于:https://www.cnblogs.com/water-mi/p/10280504.html

Bzoj4016/洛谷P2993 [FJOI2014] 最短路径树问题(最短路径问题+长链剖分/点分治)相关推荐

  1. 对LCA、树上倍增、树链剖分(重链剖分长链剖分)和LCT(Link-Cut Tree)的学习

    LCA what is LCA & what can LCA do LCA(Lowest Common Ancestors),即最近公共祖先 在一棵树上,两个节点的深度最浅的公共祖先就是 L ...

  2. YBTOJ:最短时间(长链剖分、线段树)

    解析 不难得到最优策略:先尽可能的快的送死直到路径畅通无组,然后一口气冲到t点. 现在的难点就在于如何尽可能的快的送掉特定的次数. 不难发现,花费时间关于死亡次数的函数必然是一个下凸包. 设 fx,i ...

  3. UOJ#284-快乐游戏鸡【长链剖分,线段树】

    正题 题目链接:https://uoj.ac/problem/284 题目大意 nnn个点的一棵树,每个点有一个wiw_iwi​表示至少死亡wiw_iwi​次才能通过这个点,否则就会死亡.只能往子节点 ...

  4. P3899 [湖南集训]更为厉害(线段树合并、长链剖分、二维数点)

    P3899 [湖南集训]更为厉害 若 deepb<deepa\text{deep}_b<\text{deep}_adeepb​<deepa​:c 在点 a 的子树中,根据乘法原理计算 ...

  5. [LOJ3014][JOI 2019 Final]独特的城市——树的直径+长链剖分

    题目链接: [JOI 2019 Final]独特的城市 对于每个点,它的答案最大就是与它距离最远的点的距离. 而如果与它距离为$x$的点有大于等于两个,那么与它距离小于等于$x$的点都不会被计入答案. ...

  6. 树链剖分之长链剖分 详解 题目整理

    树链剖分 题目中出现的树链剖分一般分为两种,重链剖分和长链剖分 重链剖分:选择子树最大的儿子, 将其归入当前点所在 的同一条重链 长链剖分:选择向下能达到的深 度最深的儿子,将其归 入当前点所在的同一 ...

  7. 点分治问题 ----------- P2993 [FJOI2014]最短路径树问题 [最短路径树+点分治+采坑]

    题目链接 解题思路: 首先我们知道最小路径树实际上就是Dijkstra算法在找最短路的时候转移的过程就是一个最短路径树. 那么我们就可以先跑个最短路,记录一下各个最短路的路径.然后就是很裸的点分治.分 ...

  8. 专题·树链剖分【including 洛谷·【模板】树链剖分

    初见安~~~终于学会了树剖~~~ [兴奋]当初机房的大佬在学树剖的时候我反复强调过:"学树剖没有前途的!!!" 恩.真香. 一.重链与重儿子 所谓树剖--树链剖分,就是赋予一个链的 ...

  9. 洛谷 p3372 模板-线段树 1

    题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.求出某区间每一个数的和 输入输出格式 输入格式: 第一行包含两个整数N.M,分别表示该数列数字的个数和操作的总个 ...

最新文章

  1. echarts y轴添加点击事件_ECharts中的事件和行为
  2. 中科院遗传发育所白洋组项目聘用工作人员招聘启事
  3. DS-5/RVDS4.0变量初始化错误
  4. C++指针地址内存,数据结构,文件操控
  5. threading多线程模块
  6. matlab中存档算法代码,MATLAB 智能算法超级学习手册中程序代码
  7. turtle python tkinter_【案例】 什么?idle 中竟然有内置 turtle 样例?(paint)
  8. 现代JavaScript中的精美图案:制冰厂
  9. 《C++ Primer 5th》笔记(5 / 19):语句
  10. python可变类型做默认参数
  11. 是的,解禁了,是胜利还是嘲讽?
  12. 高通about.html 文件,关于高通校准调用文件的说明文档
  13. 计算机应用数学,计算机应用数学.PDF
  14. 《数值分析》-- 数值计算中的误差与有效数字
  15. 软硬件交互 - 扫码枪
  16. 如何提取PDF文件中的图片
  17. 计算机支架式教学案例,万紫千红总是春--支架式教学(网友来稿)
  18. 字节跳动---雀魂启动
  19. Java——OOP三大特性之封装性(Encapsulation)通俗详细
  20. Spark RDD 持久化

热门文章

  1. python commands_python commands模块在python3.x被subprocess取代
  2. php intval 变小,php intval() 小数时安全漏洞分析
  3. php7可以做什么开发,php7 图形用户界面GUI 开发怎么做?看完这个代码你就明白了...
  4. linux服务器调用端口超时,Linux服务器可以ping,但是telnet端口超时,网站wget超时,访问超时的解决办法...
  5. php连接基础方法怎么查询数据库,php基础之连接mysql数据库和查询数据
  6. linux查看安装的所有内核,Linux怎么查看系统已安装内核
  7. 微信小程序开发第二弹
  8. python【力扣LeetCode算法题库】面试题 01.07- 旋转矩阵
  9. Comet OJ - 模拟赛 #2 Day2
  10. 字段对应数组_字段不同的多个工作薄汇总? 还要固定字段位置 !难不倒我!...