Description

给一个包含n个点,m条边的无向连通图。从顶点1出发,往其余所有点分别走一次并返回。
往某一个点走时,选择总长度最短的路径走。若有多条长度最短的路径,则选择经过的顶点序列字典序最小的那条路径(如路径A为1,32,11,路径B为1,3,2,11,路径B字典序较小。注意是序列的字典序的最小,而非路径中节点编号相连的字符串字典序最小)。到达该点后按原路返回,然后往其他点走,直到所有点都走过。
可以知道,经过的边会构成一棵最短路径树。请问,在这棵最短路径树上,最长的包含K个点的简单路径长度为多长?长度为该最长长度的不同路径有多少条?
这里的简单路径是指:对于一个点最多只经过一次的路径。不同路径是指路径两端端点至少有一个不同,点A到点B的路径和点B到点A视为同一条路径。

Input

第一行输入三个正整数n,m,K,表示有n个点m条边,要求的路径需要经过K个点。接下来输入m行,每行三个正整数Ai,Bi,Ci(1<=Ai,Bi<=n,1<=Ci<=10000),表示Ai和Bi间有一条长度为Ci的边。数据保证输入的是连通的无向图。

Output

输出一行两个整数,以一个空格隔开,第一个整数表示包含K个点的路径最长为多长,第二个整数表示这样的不同的最长路径有多少条。

Sample Input

6 6 4
1 2 1
2 3 1
3 4 1
2 5 1
3 6 1
5 6 1

Sample Output

3 4

HINT

对于所有数据n<=30000,m<=60000,2<=K<=n。
数据保证最短路径树上至少存在一条长度为K的路径。

题解

看错题意,以为是求包含 $k$ 个点的简单路径共多少条。调了好久...

首先求字典序最小的最短路树,考虑将边拆成两条单向边,然后按终点从大到小排序,按序插入链式前向星中,保证找到的第一条最短路就是字典序最小的。

点分就比较裸了,记深度为 $i$ 时最大的路径长度为 $sum_i$ ,长度为 $sum_i$ ,且深度为 $i$ 的路径数为 $cnt_i$ 直接转移就好了。

 //It is made by Awson on 2018.1.4
#include <set>
#include <map>
#include <cmath>
#include <ctime>
#include <queue>
#include <stack>
#include <cstdio>
#include <string>
#include <vector>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define LL long long
#define LD long double
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
using namespace std;
const int N = ;
const int M = ;
const int INF = ~0u>>; int n, m, k;
struct tt {
int to, next, cost;
}edge[(N<<)+];
int path[N+], top, ans1, ans2;
void add(int u, int v, int c) {
edge[++top].to = v;
edge[top].next = path[u];
edge[top].cost = c;
path[u] = top;
} namespace SPFA {
int a, b, c;
struct ss {
int u, v, c;
ss() {}
ss(int _u, int _v, int _c) {
u = _u, v = _v, c = _c;
}
bool operator < (const ss &b) const {
return v > b.v;
}
}w[(M<<)+];
struct sss {
int to, next, cost;
}edge[(M<<)+];
int path[N+], top, tot, pre[N+], vis[N+], prec[N+];
LL dist[N+];
void add_e(int u, int v, int c) {
edge[++top].to = v;
edge[top].cost = c;
edge[top].next = path[u];
path[u] = top;
}
void spfa() {
memset(dist, /, sizeof(dist)); dist[] = ;
queue<int>Q; Q.push(); vis[] = ;
while (!Q.empty()) {
int u = Q.front(); Q.pop(); vis[u] = ;
for (int i = path[u]; i; i = edge[i].next)
if (dist[edge[i].to] > dist[u]+edge[i].cost) {
dist[edge[i].to] = dist[u]+edge[i].cost;
pre[edge[i].to] = u, prec[edge[i].to] = edge[i].cost;
if (!vis[edge[i].to]) {
vis[edge[i].to] = ; Q.push(edge[i].to);
}
}
}
}
void main() {
scanf("%d%d%d", &n, &m, &k);
for (int i = ; i <= m; i++) {
scanf("%d%d%d", &a, &b, &c);
w[++tot] = ss(a, b, c), w[++tot] = ss(b, a, c);
}
sort(w+, w++tot);
for (int i = ; i <= tot; i++) add_e(w[i].u, w[i].v, w[i].c);
spfa();
for (int i = ; i <= n; i++) add(pre[i], i, prec[i]), add(i, pre[i], prec[i]);
}
}
namespace Point_divide {
int size[N+], mx[N+], minsize, root, vis[N+], cnt[N+], sum[N+];
void get_size(int o, int fa) {
size[o] = , mx[o] = ;
for (int i = path[o]; i; i = edge[i].next)
if (edge[i].to != fa && !vis[edge[i].to]) {
get_size(edge[i].to, o);
size[o] += size[edge[i].to];
mx[o] = Max(mx[o], size[edge[i].to]);
}
}
void get_root(int o, int rt, int fa) {
mx[o] = Max(mx[o], size[rt]-size[o]);
if (mx[o] < minsize) minsize = mx[o], root = o;
for (int i = path[o]; i; i = edge[i].next)
if (edge[i].to != fa && !vis[edge[i].to]) get_root(edge[i].to, rt, o);
}
void get_ans(int o, int fa, int dep, int cost) {
if (dep >= k) return;
if (cnt[k--dep] && ans1 < cost+sum[k--dep]) ans1 = cost+sum[k--dep], ans2 = cnt[k--dep];
else if (cnt[k--dep] && ans1 == cost+sum[k--dep]) ans2 += cnt[k--dep];
for (int i = path[o]; i; i = edge[i].next)
if (edge[i].to != fa && !vis[edge[i].to]) get_ans(edge[i].to, o, dep+, cost+edge[i].cost);
}
void get_update(int o, int fa, int dep, int cost) {
if (dep >= k) return;
if (sum[dep] < cost) sum[dep] = cost, cnt[dep] = ;
else if (sum[dep] == cost) ++cnt[dep];
for (int i = path[o]; i; i = edge[i].next)
if (edge[i].to != fa && !vis[edge[i].to]) get_update(edge[i].to, o, dep+, cost+edge[i].cost);
}
void get_clean(int o, int fa, int dep) {
if (dep >= k) return;
cnt[dep] = , sum[dep] = ;
for (int i = path[o]; i; i = edge[i].next)
if (edge[i].to != fa && !vis[edge[i].to]) get_clean(edge[i].to, o, dep+);
}
void work(int o) {
minsize = INF;
get_size(o, ), get_root(o, o, );
vis[root] = ; cnt[] = ;
for (int i = path[root]; i; i = edge[i].next)
if (!vis[edge[i].to]) get_ans(edge[i].to, root, , edge[i].cost), get_update(edge[i].to, root, , edge[i].cost);
cnt[] = ;
for (int i = path[root]; i; i = edge[i].next)
if (!vis[edge[i].to]) get_clean(edge[i].to, root, );
for (int i = path[root]; i; i = edge[i].next)
if (!vis[edge[i].to]) work(edge[i].to);
}
void main() {work(); }
}
void work() {
SPFA::main();
Point_divide::main();
printf("%d %d\n", ans1, ans2);
}
int main() {
work();
return ;
}

[FJOI 2014]最短路径树问题的更多相关文章

  1. bzoj 4016: [FJOI2014]最短路径树问题

    bzoj4016 最短路路径问题 Time Limit: 5 Sec Memory Limit: 512 MB Description 给一个包含n个点,m条边的无向连通图.从顶点1出发,往其余所有点 ...

  2. [BZOJ4016][FJOI2014]最短路径树问题

    [BZOJ4016][FJOI2014]最短路径树问题 试题描述 给一个包含n个点,m条边的无向连通图.从顶点1出发,往其余所有点分别走一次并返回. 往某一个点走时,选择总长度最短的路径走.若有多条长 ...

  3. HDU4871 Shortest-path tree(最短路径树 + 树的点分治)

    题目大概要先求一张边有权的图的根为1的最短路径树,要满足根到各点路径序列的字典序最小:然后求这棵最短路径树包含k个结点的最长路径的长度和个数. 首先先构造出这棵字典序最小的最短路径树..好吧,我太傻逼 ...

  4. POJ3013 Big Christmas Tree(最短路径树)

    题目大概说给一张点和边都有权的图,现在要求其一棵以1结点为根的生成树使树的边权和最小,树边权 = 对应的图边权 * 树边末端点为根的子树所有结点对于图顶点的点权和. 要求∑(边权*子树点权和),等价于 ...

  5. LA 4080 (多源最短路径+边修改+最短路径树)

    题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=32266 题目大意:①先求任意两点间的最短路径累加和,其中不连通的边 ...

  6. bzoj 4016 [FJOI2014]最短路径树问题(最短路径树+树分治)

    4016: [FJOI2014]最短路径树问题 Time Limit: 5 Sec  Memory Limit: 512 MBSubmit: 426  Solved: 147[Submit][Stat ...

  7. [FJOI2014]最短路径树问题

    Description 给一个包含n个点,m条边的无向连通图.从顶点1出发,往其余所有点分别走一次并返回. 往某一个点走时,选择总长度最短的路径走.若有多条长度最短的路径,则选择经过的顶点序列字典序最 ...

  8. BZOJ_4016_[FJOI2014]最短路径树问题_最短路+点分治

    BZOJ_4016_[FJOI2014]最短路径树问题_最短路+点分治 Description 给一个包含n个点,m条边的无向连通图.从顶点1出发,往其余所有点分别走一次并返回. 往某一个点走时,选择 ...

  9. 【BZOJ-4016】最短路径树问题 Dijkstra + 点分治

    4016: [FJOI2014]最短路径树问题 Time Limit: 5 Sec  Memory Limit: 512 MBSubmit: 1092  Solved: 383[Submit][Sta ...

随机推荐

  1. web服务器学习3---httpd 2.4.29日志处理

    .rotarelogs分割工具 如果有虚拟主机在虚拟主机配置文件中配置,否则在主配置文件中修改. 1.1修改配置文件 vi /usr/local/httpd/conf/conf.d/vhosts.co ...

  2. Go语言标准库_输入/输出

    Go语言标准库_输入/输出 转载节选自<Go语言标准库> Reader 接口 type Reader interface { Read(p []byte) (n int, err erro ...

  3. 从PRISM开始学WPF

    我最近打算学习WPF ,在寻找MVVM框架的时候发现了PRISM,在此之前还从一些博客上了解了其他的MVVM框架,比如浅谈WPF中的MVVM框架--MVVMFoundation 中提到的MVVMFou ...

  4. 记录python接口自动化测试--主函数(第六目)

    把操作excel的方法封装好后,就可以用准备好的接口用例来循环遍历了 我的接口测试用例如下 主函数代码: run_handle_excel.py# coding:utf-8 from base.run ...

  5. Beta冲刺-用户测试报告

    一.项目概述 1.1项目名称 高校学生征信系统 1.2项目简介 此项目基于SSH框架,力图为学生提供征信服务和信用相关的借款和申请活动.其中以信用统计和管理为主,信用使用为辅,构建出一个集信用收集和使 ...

  6. Bate敏捷冲刺每日报告--day4

    1 团队介绍 团队组成: PM:齐爽爽(258) 小组成员:马帅(248),何健(267),蔡凯峰(285)  Git链接:https://github.com/WHUSE2017/C-team 2 ...

  7. python functools.lru_cache做备忘功能

    import time import functools def clock(func): @functools.wraps(func)#还原被装饰函数的__name__和__doc__属性 def ...

  8. python API的安全认证

    我们根据pid加客户端的时间戳进行加密md5(pid|时间戳)得到的单向加密串,与时间戳,或者其它字段的串的url给服务端. 服务端接收到请求的url进行分析 客户端时间与服务端的时间戳之差如果大于规 ...

  9. DenseNet

    特点: dense shortcut connections 结构: DenseNet 是一种具有密集连接的卷积神经网络.在该网络中,任何两层之间都有直接的连接,也就是说,网络每一层的输入都是前面所有 ...

  10. 在wamp集成环境下安装laravel5.2.*框架

    虽然官方一直强烈推荐使用homestead,但是这个相对麻烦一点,所以我还是选择使用wamp集成开发环境.还有这里我只讲解windows系统下的安装,其他例如mac或linux就不写了,此文章是面向刚 ...