先跑出最短路的图, 然后对于每个点按照序号从小到大访问孩子, 就可以搞出符合题目的树了. 然后就是经典的点分治做法了. 时间复杂度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]最短路径树问题( 最短路 + 点分治 )的更多相关文章

  1. bzoj 4016 [FJOI2014]最短路径树问题(最短路径树+树分治)

    4016: [FJOI2014]最短路径树问题 Time Limit: 5 Sec  Memory Limit: 512 MBSubmit: 426  Solved: 147[Submit][Stat ...

  2. bzoj 4016: [FJOI2014]最短路径树问题

    bzoj4016 最短路路径问题 Time Limit: 5 Sec Memory Limit: 512 MB Description 给一个包含n个点,m条边的无向连通图.从顶点1出发,往其余所有点 ...

  3. BZOJ 4016 [FJOI2014]最短路径树问题 (贪心+点分治)

    题目大意:略 传送门 硬是把两个题拼到了一起= = $dijkstra$搜出单源最短路,然后$dfs$建树,如果$dis_{v}=dis_{u}+e.val$,说明这条边在最短路图内,然后像$NOIP ...

  4. [BZOJ4016][FJOI2014]最短路径树问题(dijkstra+点分治)

    4016: [FJOI2014]最短路径树问题 Time Limit: 5 Sec  Memory Limit: 512 MBSubmit: 1796  Solved: 625[Submit][Sta ...

  5. 【BZOJ4016】[FJOI2014]最短路径树问题(点分治,最短路)

    [BZOJ4016][FJOI2014]最短路径树问题(点分治,最短路) 题面 BZOJ 洛谷 题解 首先把最短路径树给构建出来,然后直接点分治就行了. 这个东西似乎也可以长链剖分,然而没有必要. # ...

  6. BZOJ_4016_[FJOI2014]最短路径树问题_最短路+点分治

    BZOJ_4016_[FJOI2014]最短路径树问题_最短路+点分治 Description 给一个包含n个点,m条边的无向连通图.从顶点1出发,往其余所有点分别走一次并返回. 往某一个点走时,选择 ...

  7. 【BZOJ4016】[FJOI2014]最短路径树问题

    [BZOJ4016][FJOI2014]最短路径树问题 题面 bzoj 洛谷 题解 虽然调了蛮久,但是思路还是蛮简单的2333 把最短路径树构出来,然后点分治就好啦 ps:如果树构萎了,这组数据可以卡 ...

  8. [FJOI2014]最短路径树问题 长链剖分

    [FJOI2014]最短路径树问题 LG传送门 B站传送门 长链剖分练手好题. 如果你还不会长链剖分的基本操作,可以看看我的总结. 这题本来出的很没水平,就是dijkstra(反正我是不用SPFA)的 ...

  9. 洛谷 [FJOI2014]最短路径树问题 解题报告

    [FJOI2014]最短路径树问题 题目描述 给一个包含\(n\)个点,\(m\)条边的无向连通图.从顶点\(1\)出发,往其余所有点分别走一次并返回. 往某一个点走时,选择总长度最短的路径走.若有多 ...

随机推荐

  1. OAuth2.0开发指南

    OAuth2.0开发指南 1.认证与登录 来往开放平台支持3种不同的OAuth 2.0验证与授权流程: 服务端流程(协议中Authorization Code Flow): 此流程适用于在Web服务端 ...

  2. ASP.NET之自定义异步HTTP处理程序(图文教程)

    前面我们学习了关于关于自定义同步HTTP处理程序,相信大家可能感觉有所成就,但是这种同步的机制只能对付客户访问较少的情况或者数据处理量不大的情况,而今天这篇文章就是解决同步HTTP处理程序的这个致命缺 ...

  3. windows7旗舰版64位下安装、破解及执行QTP11报错

    说明:假设你出现了下面几种情况,希望能解决你的问题:假设没有,就当路过. 1.安装qtp11时报vc++ 2005缺少,但怎么也不能安装成功 解决方法: 1.找到qtp安装包里面的vc++ 2005组 ...

  4. input file 样式以及获取选择文件方法集合

    样式一(http://www.cnblogs.com/jason-liu-blogs/archive/2013/06/13/3133377.html) <style> a{display: ...

  5. HTML4如何让一个DIV居中对齐?float输入日志标题

    float:left,right clear:both 如何让一个DIV居中对齐? 第一步:设置外层的DIV的text-align:center; 第二步:设置里层的DIV的margin:auto 以 ...

  6. javascript 里找元素操作元素

      javascript  一.找到元素. var d = document.getElementById("") var d = document.getElementsByNa ...

  7. jQuery 随滚动条滚动效果 (适用于内容页长文章)

    直接入题! 当内容页比较长的时候,网站右侧一直是空白,不如放点有用的东西给用户看,最好不要放广告,因为那样很邪恶,你懂的. 好吧,昨天写了这个东西,jQuery滚动随动区块,代码如下: //侧栏随动 ...

  8. Deepin 15.3 下罗技蓝牙键盘连接

    Deepin 15.3中,由于罗技蓝牙键盘需要配对码,所以无法在设置界面连接,本次尝试通过bluetoothctl软件,成功连接,步骤如下: 1.打开系统蓝牙 sudo service bluetoo ...

  9. css 问题总结

    background: <color> <image> <position> <attachment> <repeat>本文来自:佳木中国( ...

  10. C++箴言:理解 new-handler的行为

    当 operator new 不能满足一个内存分配请求时,它抛出一个 exception(异常).很久以前,他返回一个 null pointer(空指针),而一些比较老的编译器还在这样做.你依然能达到 ...