
先跑出最短路的图, 然后对于每个点按照序号从小到大访问孩子, 就可以搞出符合题目的树了. 然后就是经典的点分治做法了. 时间复杂度O(M log N + N log N)
----------------------------------------------------------------------------
#include<queue>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 30009;
const int INF = 0X3F3F3F3F;
inline int getint() {
char c = getchar();
for(; !isdigit(c); c = getchar());
int ret = 0;
for(; isdigit(c); c = getchar())
ret = ret * 10 + c - '0';
return ret;
}
int N, K, n = 0;
int d[maxn], seq[maxn << 1], w[maxn << 1], r[maxn << 1], L[maxn], R[maxn];
bool vis[maxn];
inline void Max(int &x, int t) {
if(t > x) x = t;
}
struct edge {
int t, w;
bool f;
edge* n;
} E[maxn << 2], *pt = E, *H[maxn];
inline void AddEdge(int u, int v, int w) {
pt->f = 0, pt->t = v, pt->w = w, pt->n = H[u], H[u] = pt++;
}
struct node {
int n, w;
node(int _n, int _w) : n(_n), w(_w) {
}
bool operator < (const node &o) const {
return w > o.w;
}
};
priority_queue<node> q;
void Dijkstra() {
for(int i = 0; i < N; i++) d[i] = INF;
d[0] = 0;
q.push(node(0, 0));
while(!q.empty()) {
node o = q.top(); q.pop();
if(d[o.n] != o.w) continue;
for(edge* e = H[o.n]; e; e = e->n) if(d[e->t] > d[o.n] + e->w) {
d[e->t] = d[o.n] + e->w;
q.push(node(e->t, d[e->t]));
}
}
}
void Init() {
N = getint();
int m = getint();
K = getint();
while(m--) {
int u = getint() - 1, v = getint() - 1, w = getint();
AddEdge(u, v, w), AddEdge(v, u, w);
}
}
namespace F {
edge E[maxn << 1], *pt = E, *H[maxn];
bool vis[maxn];
int L[maxn], cnt[maxn], sz[maxn];
int Root, mn, n, ans, tot;
inline void AddEdge(int u, int v, int w) {
pt->t = v, pt->w = w, pt->n = H[u], H[u] = pt++;
}
void DFS(int x, int fa = -1) {
int mx = 0;
sz[x] = 1;
for(edge* e = H[x]; e; e = e->n) if(e->t != fa && !vis[e->t]) {
DFS(e->t, x);
sz[x] += sz[e->t];
Max(mx, sz[e->t]);
}
Max(mx, n - sz[x]);
if(mx < mn)
mn = mx, Root = x;
}
void dfs_upd(int x, int fa, int d, int c) {
if(c >= K) return;
if(cnt[K - c - 1] && d + L[K - c - 1] > ans)
ans = d + L[K - c - 1], tot = cnt[K - c - 1];
else if(d + L[K - c - 1] == ans)
tot += cnt[K - c - 1];
c++;
for(edge* e = H[x]; e; e = e->n)
if(e->t != fa && !vis[e->t]) dfs_upd(e->t, x, d + e->w, c);
}
void dfs_add(int x, int fa, int d, int c) {
if(c >= K) return;
if(d > L[c])
L[c] = d, cnt[c] = 1;
else if(d == L[c])
cnt[c]++;
c++;
for(edge* e = H[x]; e; e = e->n)
if(e->t != fa && !vis[e->t]) dfs_add(e->t, x, d + e->w, c);
}
void Solve(int x) {
mn = maxn, DFS(x);
for(int i = 0; i <= sz[x]; i++) L[i] = cnt[i] = 0;
x = Root;
cnt[0] = 1;
for(edge* e = H[x]; e; e = e->n) if(!vis[e->t]) {
dfs_upd(e->t, x, e->w, 1);
dfs_add(e->t, x, e->w, 1);
}
DFS(x);
vis[x] = true;
for(edge* e = H[x]; e; e = e->n)
if(!vis[e->t]) n = sz[e->t], Solve(e->t);
}
void Work() {
for(int i = 0; i < N; i++)
vis[i] = false;
ans = tot = 0;
n = N;
Solve(0);
printf("%d %d\n", ans, tot);
}
}
bool Cmp(const int &l, const int &r) {
return seq[l] < seq[r];
}
void dfs(int x) {
seq[L[x] = ++n] = x;
r[n] = n;
vis[x] = true;
for(edge* e = H[x]; e; e = e->n) if(!vis[e->t] && d[e->t] == d[x] + e->w) {
seq[++n] = e->t;
w[n] = e->w;
r[n] = n;
}
R[x] = n;
sort(r + L[x], r + R[x] + 1, Cmp);
for(int i = L[x]; i <= R[x]; i++) if(!vis[seq[r[i]]]) {
F::AddEdge(x, seq[r[i]], w[r[i]]);
F::AddEdge(seq[r[i]], x, w[r[i]]);
dfs(seq[r[i]]);
}
}
void Build() {
for(int i = 0; i < N; i++) vis[i] = false;
dfs(0);
}
int main() {
Init();
Dijkstra();
Build();
F::Work();
return 0;
}
----------------------------------------------------------------------------
- bzoj 4016 [FJOI2014]最短路径树问题(最短路径树+树分治)
4016: [FJOI2014]最短路径树问题 Time Limit: 5 Sec Memory Limit: 512 MBSubmit: 426 Solved: 147[Submit][Stat ...
- bzoj 4016: [FJOI2014]最短路径树问题
bzoj4016 最短路路径问题 Time Limit: 5 Sec Memory Limit: 512 MB Description 给一个包含n个点,m条边的无向连通图.从顶点1出发,往其余所有点 ...
- BZOJ 4016 [FJOI2014]最短路径树问题 (贪心+点分治)
题目大意:略 传送门 硬是把两个题拼到了一起= = $dijkstra$搜出单源最短路,然后$dfs$建树,如果$dis_{v}=dis_{u}+e.val$,说明这条边在最短路图内,然后像$NOIP ...
- [BZOJ4016][FJOI2014]最短路径树问题(dijkstra+点分治)
4016: [FJOI2014]最短路径树问题 Time Limit: 5 Sec Memory Limit: 512 MBSubmit: 1796 Solved: 625[Submit][Sta ...
- 【BZOJ4016】[FJOI2014]最短路径树问题(点分治,最短路)
[BZOJ4016][FJOI2014]最短路径树问题(点分治,最短路) 题面 BZOJ 洛谷 题解 首先把最短路径树给构建出来,然后直接点分治就行了. 这个东西似乎也可以长链剖分,然而没有必要. # ...
- BZOJ_4016_[FJOI2014]最短路径树问题_最短路+点分治
BZOJ_4016_[FJOI2014]最短路径树问题_最短路+点分治 Description 给一个包含n个点,m条边的无向连通图.从顶点1出发,往其余所有点分别走一次并返回. 往某一个点走时,选择 ...
- 【BZOJ4016】[FJOI2014]最短路径树问题
[BZOJ4016][FJOI2014]最短路径树问题 题面 bzoj 洛谷 题解 虽然调了蛮久,但是思路还是蛮简单的2333 把最短路径树构出来,然后点分治就好啦 ps:如果树构萎了,这组数据可以卡 ...
- [FJOI2014]最短路径树问题 长链剖分
[FJOI2014]最短路径树问题 LG传送门 B站传送门 长链剖分练手好题. 如果你还不会长链剖分的基本操作,可以看看我的总结. 这题本来出的很没水平,就是dijkstra(反正我是不用SPFA)的 ...
- 洛谷 [FJOI2014]最短路径树问题 解题报告
[FJOI2014]最短路径树问题 题目描述 给一个包含\(n\)个点,\(m\)条边的无向连通图.从顶点\(1\)出发,往其余所有点分别走一次并返回. 往某一个点走时,选择总长度最短的路径走.若有多 ...
随机推荐
- paip.oracle10g dmp文件导入总结
paip.oracle10g dmp文件导入总结 作者Attilax , EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http://blog.csdn.net ...
- Windowsclient开发简单介绍(四)
在上一篇文章里,我简单扼要的给大家介绍了一下GDI的基础知识,包含DC,HDC.GDI对象等等,总的来说都是些偏理论的知识,属于概念的范畴. 今天这篇文章里,我就要正式開始有点实际的东 ...
- Flash Recovery Area 的备份
Flash Recovery Area 的备份 备份命令是Flash recovery Area,该命令是Oracle 10g以后才有的.10g引进了flash recovery area,同时在rm ...
- 【最大团】【HDU1530】【Maximum Clique】
先上最大团定义: 最大团问题(Maximum Clique Problem, MCP)是图论中一个经典的组合优化问题,也是一类NP完全问题,在国际上已有广泛的研究,而国内对MCP问题的研究则还处于起步 ...
- 必须知道的ADO.NET 数据库连接池
http://www.cnblogs.com/liuhaorain/archive/2012/02/19/2353110.html 题外话 通过前几章的学习,不知道大家对ADO.NET有一定的了解了没 ...
- Node.js服务的重启与监控
开始:Node +服务文件名 停止:直接快捷键Ctrl+C 监控:1.安装 npm install supervisor -g, 2.supervisor app.js 参考:http://blog. ...
- js实现超过长度的字符截取指定长度(中文字符算2个字符),超出部分以...显示
//超过长度的字符截取指定长度,超出部分以...显示 function subString(str, len) { var newLength = 0; var newStr = "&quo ...
- hdu1004Let the Balloon Rise
Problem Description Contest time again! How excited it is to see balloons floating around. But to te ...
- Docker终极指南:为什么Docker能做这么多事
Docker终极指南:为什么Docker能做这么多事 http://www.aboutyun.com/thread-11499-1-1.html
- Marshal 类的内存操作的一般功能
Marshal类 提供了一个方法集,这些方法用于分配非托管内存.复制非托管内存块.将托管类型转换为非托管类型,此外还提供了在与非托管代码交互时使用的其他杂项方法. 命名空间:System.Runtim ...