先用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. django 自带的验证功能

    django.contrib.auth提供了很多验证方法 authenticate(): 提供了用户认证,在自带的数据库表中验证用户名和密码,需要username和password两个关键字参数 如果 ...

  2. sql CET实现循环

    表结构 CREATE TABLE city( id INT IDENTITY(1,1) PRIMARY KEY, NAME NVARCHAR(100), ParentID INT , Parents ...

  3. google chrome浏览器自动填充解决方案

    在chrome浏览器中,浏览器对于[1]type为password和text的.[2]带有name或者id属性的<input>标签会有自动填充表单功能,虽然会给用户记住密码带来一定的便利, ...

  4. SpringMVC中RequetContextListener

    来自:https://www.cnblogs.com/softidea/p/7068196.html 零.引言 RequetContextListener从名字结尾Listener来看就知道属于监听器 ...

  5. C# 利用ITextSharp导出PDF文件

    最近项目中需要导出PDF文件,最后上网搜索了一下,发现ITextSharp比较好用,所以做了一个例子: public string ExportPDF() { //ITextSharp Usage / ...

  6. SQL datetime和smalldatetime区别

    datetime 存储大小8个字节,精确到分后的3为小数,日期范围从1753 年 1 月 1 日到 9999 年 12 月 31 日:而 smalldatetime存储大小为4个字节,精确到分,日期范 ...

  7. loadrunner如何设置所有虚拟用户只运行一次脚本?

    1,设置所有虚拟用户只运行一次脚本 进入场景conroller,如下图设置.初始化和启动Vuser设置都可以,看具体要求,但持续时间一定要选择“完成前一直运行”,这样设置就可以让所有Vuser只运行一 ...

  8. React.js 小书 Lesson4 - 前端组件化(三):抽象出公共组件类

    作者:胡子大哈 原文链接:http://huziketang.com/books/react/lesson4 转载请注明出处,保留原文链接和作者信息. 为了让代码更灵活,可以写更多的组件,我们把这种模 ...

  9. Day6上 括号匹配专项

    滑稽的题 T1 #include<iostream> #include<cstring> #include<queue> #include<algorithm ...

  10. as3.0 动态文本属性大全

    var my_fmt = new TextFormat();//常用样式 my_fmt.align = "center"; my_fmt.blockIndent = 50; //区 ...