先用dijkstra把最短路树建出来,然后就是树的质心分治了。

经过k个点的路径,要么全在子树上,要么经过根结点,因此可以分治。

如果分治的时候选点不好会变成O(n^2),比较极端的情况是比如树是一条链。

选择质心可以保证最大子树结点不超过n/2,每次递归至少减半,递归层数是O(logn)的。

找子树质心是O(n)的树形dp,枚举到根结点的路径是O(n)的。

把经过根节点并且路径上有c个结点的最长路径以及方案保存到一个map,对于一条新增的路径去查找k-c个点的路径,就可以更新答案了。

如果用的unorder_map,那么查找是O(1)的,因此分治复杂度是T(n) = 2*T(n/2) + O(n) ≈ O(nlogn)。

总体复杂度是O(mlogn + nlogn)

/*********************************************************
* ------------------ *
* author AbyssFish *
**********************************************************/
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<queue>
#include<vector>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
#include<cmath>
#include<numeric>
#include<climits>
#include<unordered_map>
using namespace std; const int maxn = +;
const int maxm = *+; typedef long long ll;
#define sInt 4
int hd[maxn], nx[maxm], to[maxm], we[maxm], ec;
#define eachedge int i = hd[u]; ~i; i = nx[i]
void init_g(int n){ memset(hd+,0xff,sInt*n); ec = ; }
void add_edge(int u,int v,int c)
{
to[ec] = v;
we[ec] = c;
nx[ec] = hd[u];
hd[u] = ec++;
} int n,m,k; int di[maxn], fe[maxn];
typedef pair<int,int> pii;
#define dist first
#define ver second
priority_queue<pii,vector<pii>,greater<pii> > q; void dijkstra()
{
memset(di+,0x3f,sInt*n); di[] = ; fe[] = -;
q.push(pii(,));
while(!q.empty()){
pii x = q.top(); q.pop();
if(x.dist != di[x.ver]) continue;
int u = x.ver;
for(int i = hd[u]; ~i; i = nx[i]){
int v = to[i];
if(di[v] > di[u] + we[i]){
di[v] = di[u]+we[i];
fe[v] = i;
q.push(pii(di[v],v));
}
else if(di[v] == di[u] + we[i] && to[fe[v]^] > u){
fe[v] = i;
}
}
}
} void rewrite(int u,int i)
{
nx[i] = hd[u];
hd[u] = i;
} void build_tree()
{
dijkstra();
init_g(n);
for(int v = ; v <= n; v++){
int e = fe[v];
int u = to[e^];
rewrite(u,e);
rewrite(v,e^);
}
} bool vis_c[maxn];
int tr_sz[maxn]; void cal_tr_sz(int u,int f)
{
int &c = tr_sz[u];
c = ;
for(eachedge){
int v = to[i];
if(v == f || vis_c[v]) continue;
c += tr_sz[v];
cal_tr_sz(v,u);
}
} int block_size;
int best, centroid;
void findCentroid(int u,int f)
{
int mx = ;
for(eachedge){
int v = to[i];
if(v == f || vis_c[v]) continue;
findCentroid(v,u);
mx = max(mx, tr_sz[v]);
}
mx = max(mx,block_size-tr_sz[u]);
if(best > mx){
best = mx;
centroid = u;
}
} typedef unordered_map<int,pii> cont;
typedef cont::iterator con_it;
//key 经过的点数,value(最长距离,方案数)
cont prv;
cont tmp; void update(cont &res,int c, const pii &np)
{
con_it it = res.find(c);
if(it != res.end()){
pii &p = it->second;
if(p.dist == np.dist) p.ver += np.ver;
else if(p.dist < np.dist) {
p = np;
}
}
else {
res.insert(make_pair(c,np));
}
} void enum_path(int u,int f,int c,int d,cont &res)
{
if(c >= k) return;
update(res,c,pii(d,)); for(eachedge){
int v = to[i];
if(v == f || vis_c[v]) continue;
enum_path(v,u,c+,d+we[i],res);
}
} int ans;
ll cnt; void divide(int rt)
{
cal_tr_sz(rt,-);
best = INT_MAX;
block_size = tr_sz[rt];
findCentroid(rt,-);
int u = centroid;
vis_c[u] = true; for(eachedge){
if(!vis_c[to[i]]) divide(to[i]);
} prv.clear();
prv.insert(make_pair(,pii(,)));
for(eachedge){
if(vis_c[to[i]]) continue;
tmp.clear();
enum_path(to[i],u,,we[i],tmp);
con_it it, it2;
for(it = tmp.begin(); it != tmp.end(); it++){
int c = it->first;
pii &p = it->second;
if((it2 = prv.find(k-c)) != prv.end()){
ll dis = it2->second.dist + p.dist;
if(dis > ans){
ans = dis; cnt = p.ver * it2->second.ver;
}
else if(dis == ans) cnt += p.ver * it2->second.ver;
}
} for(it = tmp.begin(); it != tmp.end(); it++){
int c = it->first+;
update(prv,c,it->second);
}
} vis_c[u] = false;
} void solve()
{
build_tree();
ans = cnt = ;
divide();
printf("%d %lld\n",ans,cnt);
} void init()
{
scanf("%d%d%d",&n,&m,&k);
init_g(n);
for(int i = ; i < m; i++){
int a,b,c; scanf("%d%d%d",&a,&b,&c);
add_edge(a,b,c);
add_edge(b,a,c);
}
} //#define LOCAL
int main()
{
#ifdef LOCAL
freopen("in.txt","r",stdin);
#endif
int T; scanf("%d",&T);
while(T--){
init();
solve();
}
return ;
}

HDU 4871 Shortest-path tree的更多相关文章

  1. hdu 3631 Shortest Path(Floyd)

    题目链接:pid=3631" style="font-size:18px">http://acm.hdu.edu.cn/showproblem.php?pid=36 ...

  2. HDU 5636 Shortest Path 暴力

    Shortest Path 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5636 Description There is a path graph ...

  3. HDU 5636 Shortest Path(Floyed,枚举)

    Shortest Path Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) Tot ...

  4. HDU - 3631 Shortest Path(Floyd最短路)

    Shortest Path Time Limit: 1000MS Memory Limit: 32768KB 64bit IO Format: %I64d & %I64u SubmitStat ...

  5. HDU - 4725_The Shortest Path in Nya Graph

    The Shortest Path in Nya Graph Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (J ...

  6. hdu 3631 Shortest Path

    floyd算法好像很奇妙的样子.可以做到每次加入一个点再以这个点为中间点去更新最短路,效率是n*n. #include<cstdio> #include<cstring> #i ...

  7. HDU 5636 Shortest Path

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5636 题解: 1.暴力枚举: #include<cmath> #include<c ...

  8. HDU 5636 Shortest Path 分治+搜索剪枝

    题意:bc round 74 分析(官方题解): 你可以选择分类讨论, 但是估计可能会写漏一些地方. 只要抽出新增边的端点作为关键点, 建立一个新图, 然后跑一遍floyd就好了. 复杂度大概O(6^ ...

  9. HDU 5636 Shortest Path(Floyd)

    题目链接  HDU5636 n个点,其中编号相邻的两个点之间都有一条长度为1的边,然后除此之外还有3条长度为1的边. m个询问,每次询问求两个点之前的最短路. 我们把这三条边的6个点两两算最短路, 然 ...

  10. HDU 4479 Shortest path 带限制最短路

    题意:给定一个图,求从1到N的递增边权的最短路. 解法:类似于bellman-ford思想,将所有的边先按照权值排一个序,然后依次将边加入进去更新,每条边只更新一次,为了保证得到的路径是边权递增的,每 ...

随机推荐

  1. 在U盘打造个性化PE工具箱+KALI(Persistence)+存储的工作站

    基本工具: kali-linux-2018.2-amd64 原版镜像:https://www.kali.org/downloadsWin32DiskImager yunfile 下载较慢,建议自行百度 ...

  2. .netcore在linux下使用P/invoke方式调用linux动态库

    http://www.mamicode.com/info-detail-2358309.html   .netcore下已经实现了通过p/invoke方式调用linux的动态链接库(*.so)文件 1 ...

  3. Vue.js-----轻量高效的MVVM框架(十、父子组件通信)

    #1.父链 html: <h3>#父链</h3> <div> <div>子组件可以用 this.$parent 访问它的父组件.根实例的后代可以用 th ...

  4. webstorm 常见问题

    1.webstorm(10.0.2)的端口号修改 https://blog.csdn.net/m0_38082783/article/details/71079274 2.导入主题 file –> ...

  5. Murano Weekly Meeting 2016.07.26

    Meeting time: 2016.July.26 1:00~2:00 Chairperson:  Nikolay_St, from Mirantis Meeting summary: 1.Masc ...

  6. PyCharm5 破解汉化

    作者博文地址:https://www.cnblogs.com/liu-shuai/ 破解: 将下列序列号复制到软件激活界面即可破解. 43B4A73YYJ-eyJsaWNlbnNlSWQiOiI0M0 ...

  7. linux上的常用命令

    删除目录及文件 (删除tem目录和所有.xml文件) rm -rf tem/ *.xml 复制文件 cp zoo_sample.cfg zoo.cfg 两台机的目录相互拷贝 scp -r apps/ ...

  8. Cloudera Manager卸载笔记

    1.通过管理平台分别停止组件服务和Cloudera Management Service 2.通过管理平台注销并移除Parcles (在控制台注销并移除,无论是安装的Parcles还是未安装的Parc ...

  9. 【密码学】RSA密钥长度、明文长度和密文长度

    本文介绍RSA加解密中必须考虑到的密钥长度.明文长度和密文长度问题,对第一次接触RSA的开发人员来说,RSA算是比较复杂的算法,天缘以后还会补充几篇RSA基础知识专题文章,用最简单最通俗的语言描述RS ...

  10. CentOS7 安装oracle 客户端

    参考 http://www.oracle.com/technetwork/topics/linuxx86-64soft-092277.html   下载 oracle-instantclient11. ...