
先跑出最短路的图, 然后对于每个点按照序号从小到大访问孩子, 就可以搞出符合题目的树了. 然后就是经典的点分治做法了. 时间复杂度O(M log N + N log N)
----------------------------------------------------------------------------
#include<queue>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 30009;
const int INF = 0X3F3F3F3F;
inline int getint() {
char c = getchar();
for(; !isdigit(c); c = getchar());
int ret = 0;
for(; isdigit(c); c = getchar())
ret = ret * 10 + c - '0';
return ret;
}
int N, K, n = 0;
int d[maxn], seq[maxn << 1], w[maxn << 1], r[maxn << 1], L[maxn], R[maxn];
bool vis[maxn];
inline void Max(int &x, int t) {
if(t > x) x = t;
}
struct edge {
int t, w;
bool f;
edge* n;
} E[maxn << 2], *pt = E, *H[maxn];
inline void AddEdge(int u, int v, int w) {
pt->f = 0, pt->t = v, pt->w = w, pt->n = H[u], H[u] = pt++;
}
struct node {
int n, w;
node(int _n, int _w) : n(_n), w(_w) {
}
bool operator < (const node &o) const {
return w > o.w;
}
};
priority_queue<node> q;
void Dijkstra() {
for(int i = 0; i < N; i++) d[i] = INF;
d[0] = 0;
q.push(node(0, 0));
while(!q.empty()) {
node o = q.top(); q.pop();
if(d[o.n] != o.w) continue;
for(edge* e = H[o.n]; e; e = e->n) if(d[e->t] > d[o.n] + e->w) {
d[e->t] = d[o.n] + e->w;
q.push(node(e->t, d[e->t]));
}
}
}
void Init() {
N = getint();
int m = getint();
K = getint();
while(m--) {
int u = getint() - 1, v = getint() - 1, w = getint();
AddEdge(u, v, w), AddEdge(v, u, w);
}
}
namespace F {
edge E[maxn << 1], *pt = E, *H[maxn];
bool vis[maxn];
int L[maxn], cnt[maxn], sz[maxn];
int Root, mn, n, ans, tot;
inline void AddEdge(int u, int v, int w) {
pt->t = v, pt->w = w, pt->n = H[u], H[u] = pt++;
}
void DFS(int x, int fa = -1) {
int mx = 0;
sz[x] = 1;
for(edge* e = H[x]; e; e = e->n) if(e->t != fa && !vis[e->t]) {
DFS(e->t, x);
sz[x] += sz[e->t];
Max(mx, sz[e->t]);
}
Max(mx, n - sz[x]);
if(mx < mn)
mn = mx, Root = x;
}
void dfs_upd(int x, int fa, int d, int c) {
if(c >= K) return;
if(cnt[K - c - 1] && d + L[K - c - 1] > ans)
ans = d + L[K - c - 1], tot = cnt[K - c - 1];
else if(d + L[K - c - 1] == ans)
tot += cnt[K - c - 1];
c++;
for(edge* e = H[x]; e; e = e->n)
if(e->t != fa && !vis[e->t]) dfs_upd(e->t, x, d + e->w, c);
}
void dfs_add(int x, int fa, int d, int c) {
if(c >= K) return;
if(d > L[c])
L[c] = d, cnt[c] = 1;
else if(d == L[c])
cnt[c]++;
c++;
for(edge* e = H[x]; e; e = e->n)
if(e->t != fa && !vis[e->t]) dfs_add(e->t, x, d + e->w, c);
}
void Solve(int x) {
mn = maxn, DFS(x);
for(int i = 0; i <= sz[x]; i++) L[i] = cnt[i] = 0;
x = Root;
cnt[0] = 1;
for(edge* e = H[x]; e; e = e->n) if(!vis[e->t]) {
dfs_upd(e->t, x, e->w, 1);
dfs_add(e->t, x, e->w, 1);
}
DFS(x);
vis[x] = true;
for(edge* e = H[x]; e; e = e->n)
if(!vis[e->t]) n = sz[e->t], Solve(e->t);
}
void Work() {
for(int i = 0; i < N; i++)
vis[i] = false;
ans = tot = 0;
n = N;
Solve(0);
printf("%d %d\n", ans, tot);
}
}
bool Cmp(const int &l, const int &r) {
return seq[l] < seq[r];
}
void dfs(int x) {
seq[L[x] = ++n] = x;
r[n] = n;
vis[x] = true;
for(edge* e = H[x]; e; e = e->n) if(!vis[e->t] && d[e->t] == d[x] + e->w) {
seq[++n] = e->t;
w[n] = e->w;
r[n] = n;
}
R[x] = n;
sort(r + L[x], r + R[x] + 1, Cmp);
for(int i = L[x]; i <= R[x]; i++) if(!vis[seq[r[i]]]) {
F::AddEdge(x, seq[r[i]], w[r[i]]);
F::AddEdge(seq[r[i]], x, w[r[i]]);
dfs(seq[r[i]]);
}
}
void Build() {
for(int i = 0; i < N; i++) vis[i] = false;
dfs(0);
}
int main() {
Init();
Dijkstra();
Build();
F::Work();
return 0;
}
----------------------------------------------------------------------------
- bzoj 4016 [FJOI2014]最短路径树问题(最短路径树+树分治)
4016: [FJOI2014]最短路径树问题 Time Limit: 5 Sec Memory Limit: 512 MBSubmit: 426 Solved: 147[Submit][Stat ...
- bzoj 4016: [FJOI2014]最短路径树问题
bzoj4016 最短路路径问题 Time Limit: 5 Sec Memory Limit: 512 MB Description 给一个包含n个点,m条边的无向连通图.从顶点1出发,往其余所有点 ...
- BZOJ 4016 [FJOI2014]最短路径树问题 (贪心+点分治)
题目大意:略 传送门 硬是把两个题拼到了一起= = $dijkstra$搜出单源最短路,然后$dfs$建树,如果$dis_{v}=dis_{u}+e.val$,说明这条边在最短路图内,然后像$NOIP ...
- [BZOJ4016][FJOI2014]最短路径树问题(dijkstra+点分治)
4016: [FJOI2014]最短路径树问题 Time Limit: 5 Sec Memory Limit: 512 MBSubmit: 1796 Solved: 625[Submit][Sta ...
- 【BZOJ4016】[FJOI2014]最短路径树问题(点分治,最短路)
[BZOJ4016][FJOI2014]最短路径树问题(点分治,最短路) 题面 BZOJ 洛谷 题解 首先把最短路径树给构建出来,然后直接点分治就行了. 这个东西似乎也可以长链剖分,然而没有必要. # ...
- BZOJ_4016_[FJOI2014]最短路径树问题_最短路+点分治
BZOJ_4016_[FJOI2014]最短路径树问题_最短路+点分治 Description 给一个包含n个点,m条边的无向连通图.从顶点1出发,往其余所有点分别走一次并返回. 往某一个点走时,选择 ...
- 【BZOJ4016】[FJOI2014]最短路径树问题
[BZOJ4016][FJOI2014]最短路径树问题 题面 bzoj 洛谷 题解 虽然调了蛮久,但是思路还是蛮简单的2333 把最短路径树构出来,然后点分治就好啦 ps:如果树构萎了,这组数据可以卡 ...
- [FJOI2014]最短路径树问题 长链剖分
[FJOI2014]最短路径树问题 LG传送门 B站传送门 长链剖分练手好题. 如果你还不会长链剖分的基本操作,可以看看我的总结. 这题本来出的很没水平,就是dijkstra(反正我是不用SPFA)的 ...
- 洛谷 [FJOI2014]最短路径树问题 解题报告
[FJOI2014]最短路径树问题 题目描述 给一个包含\(n\)个点,\(m\)条边的无向连通图.从顶点\(1\)出发,往其余所有点分别走一次并返回. 往某一个点走时,选择总长度最短的路径走.若有多 ...
随机推荐
- ps怎样选取自己想要的图片部分(二)
上篇文章我们介绍了怎样选取所要的图形.但往往我们实际做项目的时候须要创建一个圆形图标或者椭圆形图标,这样会使得我们的图标相比矩形图标更加美观一些. 那么怎样将一个矩形图标改成圆形图标呢? 首先我们须要 ...
- GDAL1.11版本号对SHP文件索引加速測试
GDAL库中对于矢量数据的读取中能够设置一些过滤器来对矢量图形进行筛选.对于Shapefile格式来说.假设数据量太大,设置这个过滤器时间慢的简直无法忍受.好在GDAL1.10版本号開始支持读取Sha ...
- win7下安装Ubuntukylin-14.04双系统
工具准备: 下载ISO系统镜像,UltraISO,EasyBCD,分区助手,8G 优盘 U盘启动制作流程: 1,打开分区助手,从硬盘中分出空闲空间(60G)作为Ubuntu工作空间,文件系统设为Ext ...
- linode最新试用(购买)流程
最新linode官网www.linode.com可以免费试用7天,但是需要你的身份认证 第一步:注册一个linode账号email填写国内的163.126.qq邮箱是不能认证的,这里可以填写gmail ...
- Android学习之listview的下拉刷新、上拉载入
本例是在上例的基础上完成的.本例实现的listview上拉载入.下拉刷新功能,是在开源网站上别人写好的listview,主要是对listview的控件进行重写,添加了footer和header. 1. ...
- SQL高级查询的练习题
Student(S#,Sname,Sage,Ssex) 学生表 Course(C#,Cname,T#) 课程表 SC(S#,C#,score) 成绩表 Teacher(T#,Tname) 教师表 问题 ...
- 学习java的视频资源(尚学堂)(比较老旧,但是还是挺好用)
本人新手,转入IT,一开始在学校的时候看过尚学堂 马士兵讲过的java基础视频教程,这次深入学习呢,就从百度云盘找了一整套的视频资源.之后越深入的学习呢,发现这些视频资源VeryCD上都发布了,地址 ...
- css动画,css过度,js动画
1jQuery动画 语法a$(selector).animate(styles,options) 语法b$(selector).animate(styles,speed,easing,callback ...
- J2SE知识点摘记(五)
1. 引用数据类型的传递 java用引用代替C++中的指针 fun()方法接收的参数是是Change c1,也就是说说fun()方法接受的是一个对象的引用,所以fun方法中所所做的操作就 ...
- webservice axis2客户端设置代理方法(公司网络通过代理访问时)
webservice axis2客户端设置代理方法(公司网络通过代理访问时) UploadProcessInServiceStub stub = new UploadProcessInServic ...