HDU 4871 Shortest-path tree
先用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的更多相关文章
- hdu 3631 Shortest Path(Floyd)
题目链接:pid=3631" style="font-size:18px">http://acm.hdu.edu.cn/showproblem.php?pid=36 ...
- HDU 5636 Shortest Path 暴力
Shortest Path 题目连接: http://acm.hdu.edu.cn/showproblem.php?pid=5636 Description There is a path graph ...
- HDU 5636 Shortest Path(Floyed,枚举)
Shortest Path Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others) Tot ...
- HDU - 3631 Shortest Path(Floyd最短路)
Shortest Path Time Limit: 1000MS Memory Limit: 32768KB 64bit IO Format: %I64d & %I64u SubmitStat ...
- 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 ...
- hdu 3631 Shortest Path
floyd算法好像很奇妙的样子.可以做到每次加入一个点再以这个点为中间点去更新最短路,效率是n*n. #include<cstdio> #include<cstring> #i ...
- HDU 5636 Shortest Path
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5636 题解: 1.暴力枚举: #include<cmath> #include<c ...
- HDU 5636 Shortest Path 分治+搜索剪枝
题意:bc round 74 分析(官方题解): 你可以选择分类讨论, 但是估计可能会写漏一些地方. 只要抽出新增边的端点作为关键点, 建立一个新图, 然后跑一遍floyd就好了. 复杂度大概O(6^ ...
- HDU 5636 Shortest Path(Floyd)
题目链接 HDU5636 n个点,其中编号相邻的两个点之间都有一条长度为1的边,然后除此之外还有3条长度为1的边. m个询问,每次询问求两个点之前的最短路. 我们把这三条边的6个点两两算最短路, 然 ...
- HDU 4479 Shortest path 带限制最短路
题意:给定一个图,求从1到N的递增边权的最短路. 解法:类似于bellman-ford思想,将所有的边先按照权值排一个序,然后依次将边加入进去更新,每条边只更新一次,为了保证得到的路径是边权递增的,每 ...
随机推荐
- nginx编译报错
[root@vm_0_2_centos nginx-1.12.2]# ./configure --prefix=/application/nginx-1.12.2 --user=www --group ...
- JavaScript中使用ActiveXObject操作本地文件夹的方法
转载地址 http://www.jb51.net/article/48538.htm 在Windows平台上, js可以调用很多Windows提供的ActivexObject,本文就使用js来实 ...
- aerospike(2)-java client
地址:https://www.aerospike.com/download/client/java/4.3.1/ 例子顺序:https://github.com/aerospike/aerospike ...
- Netcore中实现字段和属性注入
https://www.cnblogs.com/loogn/p/10566510.html 简单来说,使用Ioc模式需要两个步骤,第一是把服务注册到容器中,第二是从容器中获取服务,我们一个一个讨论并演 ...
- vue router路由(三)
当环境搭建及Vue语法与指令都有所了解,该说下router. build目录是打包配置文件 (不建议动) config是vue项目基本配置文件 dist是构建后文件 js 手动创建 (根据需要) no ...
- Android NDK开发 JNI操作java构造方法,普通方法,静态方法(七)
Android NDK开发 JNI操作java普通.静态.构造方法 1.Jni实例化一个Java类的实例jobject 1.通过FindClas( ),获取Java类的的jclass 2.通过GetM ...
- Python操作列表
1.List Python内置的一种数据类型是列表:list.list是一种有序的集合,可以随时添加和删除其中的元素. 比如,列出班里所有同学的名字,就可以用一个list表示: >>> ...
- 编译opencv python接口
首先,安装依赖1 sudo apt-get install build-essential 2 sudo apt-get install cmake git libgtk2.0-dev pkg-con ...
- css3重点回顾字体
1.字体 免费字体下载https://cn.ffonts.net/
- SQLSERVER 自增列,值突然增大1000
SQLSERVER 自增列,值突然增大1000https://blog.csdn.net/lichxi1002/article/details/40074247