
先跑出最短路的图, 然后对于每个点按照序号从小到大访问孩子, 就可以搞出符合题目的树了. 然后就是经典的点分治做法了. 时间复杂度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\)出发,往其余所有点分别走一次并返回. 往某一个点走时,选择总长度最短的路径走.若有多 ...
随机推荐
- jqery ajax读取json文件
json文件数据 [ {"name":"哈哈··","email":"邮箱01","gender": ...
- RDLC报表系列(三) 总计和折叠
继续接上一篇的内容,本文主要是简述总计和折叠 1.在Dept列右击,选择插入行->组内部下方(每个部门的Total),插入新的一行,并拆分单元格,然后合并列 3.设置文本框属性,格式为Total ...
- 随机抽样一致性算法(RANSAC)
本文翻译自维基百科,英文原文地址是:http://en.wikipedia.org/wiki/ransac,如果您英语不错,建议您直接查看原文. RANSAC是"RANdom SAmple ...
- hbase namespace问题
如果遇到进入shell之后HMaster自动挂掉的问题,并且master的log里出现“TableExistsException: hbase:namespace”字样,很可能是更换了Hbase的版本 ...
- 由chkconfig 引发的联想——怎么查看程序是否已经安装/成功安装
由chkconfig 引发的联想--怎么查看程序是否已经安装/成功安装 某天需要运行chkconfig,root登录依然找不到该命令. [root@localhost ~]# chkconfig ba ...
- JQuery EasyUI combobox动态添加option
<input class="easyui-combobox" id="rwlb" name="rwlb" style="wi ...
- (Qt 翻译) QGLAbstractScene
QGLAbstractScene Class Reference #include <QGLAbstractScene> This class was introduced in Qt3D ...
- js删除数组里的某个元素
首先可以给js的数组对象定义一个函数,用于查找指定的元素在数组中的位置,即索引,代码为: Array.prototype.indexOf = function(val) { for (var i = ...
- jupyter巨好玩-常用设置
整理一下有用的设置: 自定义ipython工作目录 用jupyter notebook默认打开的页面时,默认在的是home路径,会看见一大堆东西,假如我们只想展示jupyter的工程目录咋办? 简单说 ...
- 自定义清除重复uses-permission申明的AS插件
分享一个我刚到天下布医工作时,写的一个android studio插件. 做安卓项目时,经常继承一些第三方sdk,这些sdk都会申请权限,导致AndroidManifest.xml中的uses-per ...