先用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. nginx编译报错

    [root@vm_0_2_centos nginx-1.12.2]# ./configure --prefix=/application/nginx-1.12.2 --user=www --group ...

  2. JavaScript中使用ActiveXObject操作本地文件夹的方法

    转载地址    http://www.jb51.net/article/48538.htm 在Windows平台上, js可以调用很多Windows提供的ActivexObject,本文就使用js来实 ...

  3. aerospike(2)-java client

    地址:https://www.aerospike.com/download/client/java/4.3.1/ 例子顺序:https://github.com/aerospike/aerospike ...

  4. Netcore中实现字段和属性注入

    https://www.cnblogs.com/loogn/p/10566510.html 简单来说,使用Ioc模式需要两个步骤,第一是把服务注册到容器中,第二是从容器中获取服务,我们一个一个讨论并演 ...

  5. vue router路由(三)

    当环境搭建及Vue语法与指令都有所了解,该说下router. build目录是打包配置文件 (不建议动) config是vue项目基本配置文件 dist是构建后文件 js 手动创建 (根据需要) no ...

  6. Android NDK开发 JNI操作java构造方法,普通方法,静态方法(七)

    Android NDK开发 JNI操作java普通.静态.构造方法 1.Jni实例化一个Java类的实例jobject 1.通过FindClas( ),获取Java类的的jclass 2.通过GetM ...

  7. Python操作列表

    1.List Python内置的一种数据类型是列表:list.list是一种有序的集合,可以随时添加和删除其中的元素. 比如,列出班里所有同学的名字,就可以用一个list表示: >>> ...

  8. 编译opencv python接口

    首先,安装依赖1 sudo apt-get install build-essential 2 sudo apt-get install cmake git libgtk2.0-dev pkg-con ...

  9. css3重点回顾字体

    1.字体 免费字体下载https://cn.ffonts.net/

  10. SQLSERVER 自增列,值突然增大1000

    SQLSERVER 自增列,值突然增大1000https://blog.csdn.net/lichxi1002/article/details/40074247