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

设$f[i][0/1]$表示到当前分治重心的路径中点数为$i$的路径最大长度和方案数

然后注意细节就可以$A$掉它了

代码:

 #include<iostream>
#include<cstdio>
#include<algorithm>
#include<queue>
#include<vector>
#include<cstring>
#define M 100010
#define inf 1e9
using namespace std;
int n,m,num,ans1,ans2,S,rt,k;
int head[M],dis[M],d[M],g[M],size[M],maxn[M],f[M][];
bool vis[M];
struct point{int to,next,dis;}e[M<<];
struct edge{int to,dis;};
struct node{int id,v;};
vector<edge>vec[M];
priority_queue<node>Q;
bool operator < (node a1,node a2) {
return a1.v>a2.v;
}
void add(int from,int to,int dis) {
e[++num].next=head[from];
e[num].to=to;
e[num].dis=dis;
head[from]=num;
}
void Dijkstra(int s) {
memset(dis,,sizeof(dis));
dis[s]=;
Q.push((node){s,});
while(!Q.empty()) {
int x=Q.top().id;Q.pop();
if(vis[x]) continue;
for(int i=;i<vec[x].size();i++) {
int to=vec[x][i].to;
if(dis[to]>dis[x]+vec[x][i].dis) {
dis[to]=dis[x]+vec[x][i].dis;
Q.push((node){to,dis[to]});
}
}
}
}
void build(int x) {
vis[x]=true;
for(int i=;i<vec[x].size();i++) {
int to=vec[x][i].to;
if(vis[to]) continue;
if(dis[x]+vec[x][i].dis==dis[to]) {
build(to);
add(x,to,vec[x][i].dis);
add(to,x,vec[x][i].dis);
}
}
}
void getroot(int x,int fa) {
size[x]=;maxn[x]=;
for(int i=head[x];i;i=e[i].next) {
int to=e[i].to;
if(to==fa||vis[to]) continue;
getroot(to,x),size[x]+=size[to];
maxn[x]=max(maxn[x],size[to]);
}
maxn[x]=max(maxn[x],S-size[x]);
if(maxn[x]<maxn[rt]) rt=x;
}
void cal(int x,int fa) {
if(d[x]>k) return;
if(ans1<g[x]+f[k-d[x]+(d[x]!=k)][]) ans1=g[x]+f[k-d[x]+(d[x]!=k)][],ans2=f[k-d[x]+(d[x]!=k)][];
else if(ans1==g[x]+f[k-d[x]+(d[x]!=k)][]) ans2+=f[k-d[x]+(d[x]!=k)][];
for(int i=head[x];i;i=e[i].next) {
int to=e[i].to;
if(to==fa||vis[to]) continue;
d[to]=d[x]+,g[to]=g[x]+e[i].dis;
cal(to,x);
}
}
void insert(int x,int fa) {
if(d[x]<=k) {
if(f[d[x]][]<g[x]) f[d[x]][]=g[x],f[d[x]][]=;
else if(f[d[x]][]==g[x]) f[d[x]][]++;
for(int i=head[x];i;i=e[i].next)
if(!vis[e[i].to]&&e[i].to!=fa)
insert(e[i].to,x);
}
}
void del(int x,int fa) {
if(d[x]<=k) {
f[d[x]][]=f[d[x]][]=-inf;
for(int i=head[x];i;i=e[i].next)
if(!vis[e[i].to]&&e[i].to!=fa)
del(e[i].to,x);
}
}
void solve(int x) {
//cout<<x<<endl;
vis[x]=true;f[][]=,f[][]=;
for(int i=head[x];i;i=e[i].next) {
int to=e[i].to;
if(vis[to]) continue;
d[to]=,g[to]=e[i].dis,cal(to,x);
insert(to,x);
}
for(int i=head[x];i;i=e[i].next)
if(!vis[e[i].to])
del(e[i].to,x);
for(int i=head[x];i;i=e[i].next) {
int to=e[i].to;
if(vis[to]) continue;
S=size[to],rt=,getroot(to,);
solve(rt);
}
}
int main() {
scanf("%d%d%d",&n,&m,&k);
memset(f,,sizeof(f));
for(int i=;i<=m;i++) {
int a,b,c;scanf("%d%d%d",&a,&b,&c);
vec[a].push_back((edge){b,c});
vec[b].push_back((edge){a,c});
}
Dijkstra(),memset(vis,,sizeof(vis)),build();
memset(vis,,sizeof(vis)),maxn[]=S=n,getroot(,);
solve(rt);printf("%d %d",ans1,ans2);
return ;
}

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

  1. BZOJ 4016 最短路径树问题 最短路径树构造+点分治

    题目: BZOJ4016最短路径树问题 分析: 大家都说这是一道强行拼出来的题,属于是两种算法的模板题. 我们用dijkstra算法算出1为源点的最短路数组,然后遍历一下建出最短路树. 之后就是裸的点 ...

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

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

  3. 【BZOJ4016】[FJOI2014]最短路径树问题

    [BZOJ4016][FJOI2014]最短路径树问题 题面 bzoj 洛谷 题解 虽然调了蛮久,但是思路还是蛮简单的2333 把最短路径树构出来,然后点分治就好啦 ps:如果树构萎了,这组数据可以卡 ...

  4. [BZOJ4016][FJOI2014]最短路径树问题(dijkstra+点分治)

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

  5. 【BZOJ4016】[FJOI2014]最短路径树问题 最短路径树+点分治

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

  6. 【BZOJ4016】[FJOI2014]最短路径树问题(点分治,最短路)

    [BZOJ4016][FJOI2014]最短路径树问题(点分治,最短路) 题面 BZOJ 洛谷 题解 首先把最短路径树给构建出来,然后直接点分治就行了. 这个东西似乎也可以长链剖分,然而没有必要. # ...

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

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

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

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

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

    浅谈树分治:https://www.cnblogs.com/AKMer/p/10014803.html 题目传送门:https://www.lydsy.com/JudgeOnline/problem. ...

随机推荐

  1. 2017 Multi-University Training Contest - Team 1—HDU6040

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6040 题意:不知道北航的同学为何解释题意之前都要想一段故事,导致刚开始题意不是很懂,题意就是给你n,m ...

  2. C/C++编译过程

    C/C++编译过程 C/C++编译过程主要分为4个过程 1) 编译预处理 2) 编译.优化阶段 3) 汇编过程 4) 链接程序 一.编译预处理 (1)宏定义指令,如#define Name Token ...

  3. find-if-an-item-is-in-a-javascript-array

    http://stackoverflow.com/questions/143847/best-way-to-find-if-an-item-is-in-a-javascript-array Best ...

  4. Storm编程模型及组件流程图

    一.Storm编程模型 二.Storm组件流程图

  5. javaweb前后台中文参数乱码

    一.描述 从前台传中文参数到后台,发现中文乱码. 二.解决 首先,统一所有文件为utf-8格式. 其次,在传参时,使用js的encodeURI函数,对参数进行编码. 然后一定要对该中文参数进行两次编码 ...

  6. 雨痕 的《Python学习笔记》--附脑图(转)

    原文:http://www.pythoner.com/148.html 近日,在某微博上看到有人推荐了 雨痕 的<Python学习笔记>,从github上下载下来看了下,确实很不错. 注意 ...

  7. Linux包管理及yum

    1.光盘挂载 mount /dev/cdrom /mntcd  /mnt 2.安装rpm包 rpm -ivh vsftpd-3.0.2-22.el7.x86_64.rpm rpm -Uvh vsftp ...

  8. Flume 1.7 源代码分析(四)从Source写数据到Channel

    Flume 1.7 源代码分析(一)源代码编译 Flume 1.7 源代码分析(二)总体架构 Flume 1.7 源代码分析(三)程序入口 Flume 1.7 源代码分析(四)从Source写数据到C ...

  9. Java集合—Map

    简介 Map用户保存具有映射关系的数据,因此Map集合里保存着两组数,一组值用户保存Map里的key,另一组值用户保存Map里的value,key和value都可以是任何引用类型的数据.Map的key ...

  10. LoadJS

    LoadJS是一个微小的异步加载器为现代浏览器(711字节). https://github.com/muicss/loadjs 介绍 LoadJS是一个微小的异步加载库的现代浏览器(IE9 +). ...