【bzoj4016】[FJOI2014]最短路径树问题 堆优化Dijkstra+DFS树+树的点分治
题目描述
输入
输出
样例输入
6 6 4
1 2 1
2 3 1
3 4 1
2 5 1
3 6 1
5 6 1
样例输出
3 4
题解
堆优化Dijkstra+DFS树+树的点分治
我会说本题难点在于求最短路径树吗?
首先题意理解了半天,还是不懂“而非路径中节点编号相连的字符串字典序最小”是啥意思,后来才发现还有这种非人类理解方法...
求题目要求的最短路径树方法:先求出最短路图(由所有构成最短路的边构成的图,对字典序没有要求),然后按照字典序求出最短路图的DFS树即为最短路径树。
证明:最短路径树一定在最短路图上,而修改字典序优先DFS树的任意一条边都会使字典序增大,因此命题得证
求出最短路径树之后就是点分治的问题了。
由于本题的点分治是固定点数的(即固定边数),因此可以直接开数组记录一下某深度的最大权值,然后使用类似于树形dp的方法来求答案。
具体地,设f[i]为当前子树深度为i的最大边权和,g[i]为之前子树以及根节点深度为i的最大边权和,那么对答案的贡献即为f[i]+g[k-1-i]。
可以证明时间复杂度最坏情况下是$O(n\log n)$的。
另外注意清空数组时不能使用memset,否则时间复杂度直接起飞。
数组多的不忍直视= =
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <utility>
#include <vector>
#define N 30010
#define inf 0x3fffffff
using namespace std;
priority_queue<pair<int , int> > q;
vector<int> v[N];
int hh[N] , tt[N << 2] , ll[N << 2] , nn[N << 2] , cc = 1 , vv[N] , dd[N] , uu[N];
int n , k , head[N] , to[N << 1] , len[N << 1] , next[N << 1] , cnt;
int vis[N] , root , sum , si[N] , bs[N] , f[N] , g[N] , sf[N] , sg[N] , md , deep[N] , dis[N] , ans , num;
void aa(int x , int y , int z)
{
tt[++cc] = y , ll[cc] = z , nn[cc] = hh[x] , hh[x] = cc;
}
void add(int x , int y , int z)
{
to[++cnt] = y , len[cnt] = z , next[cnt] = head[x] , head[x] = cnt;
}
bool cmp(int a , int b)
{
return tt[a] < tt[b];
}
void dijkstra()
{
int x , i;
memset(dd , 0x3f , sizeof(dd));
dd[1] = 0 , q.push(make_pair(0 , 1));
while(!q.empty())
{
x = q.top().second , q.pop();
if(vv[x]) continue;
vv[x] = 1;
for(i = hh[x] ; i ; i = nn[i])
if(dd[x] == dd[tt[i]] + ll[i])
v[tt[i]].push_back(i ^ 1);
for(i = hh[x] ; i ; i = nn[i])
if(dd[tt[i]] > dd[x] + ll[i])
dd[tt[i]] = dd[x] + ll[i] , q.push(make_pair(-dd[tt[i]] , tt[i]));
}
}
void dfs(int x)
{
int i;
sort(v[x].begin() , v[x].end() , cmp);
for(i = 0 ; i < (int)v[x].size() ; i ++ )
if(!uu[tt[v[x][i]]])
uu[tt[v[x][i]]] = 1 , add(x , tt[v[x][i]] , ll[v[x][i]]) , add(tt[v[x][i]] , x , ll[v[x][i]]) , dfs(tt[v[x][i]]);
}
void getroot(int x , int fa)
{
int i;
bs[x] = 0 , si[x] = 1;
for(i = head[x] ; i ; i = next[i])
if(!vis[to[i]] && to[i] != fa)
getroot(to[i] , x) , si[x] += si[to[i]] , bs[x] = max(bs[x] , si[to[i]]);
bs[x] = max(bs[x] , sum - si[x]);
if(bs[x] < bs[root]) root = x;
}
void getdeep(int x , int fa)
{
int i;
for(i = head[x] ; i ; i = next[i])
{
if(!vis[to[i]] && to[i] != fa)
{
deep[to[i]] = deep[x] + 1 , dis[to[i]] = dis[x] + len[i] , md = max(md , deep[to[i]]);
if(dis[to[i]] > f[deep[to[i]]]) f[deep[to[i]]] = dis[to[i]] , sf[deep[to[i]]] = 1;
else if(dis[to[i]] == f[deep[to[i]]]) sf[deep[to[i]]] ++ ;
getdeep(to[i] , x);
}
}
}
void query(int x)
{
int i , j , sm = 0;
vis[x] = 1;
for(i = head[x] ; i ; i = next[i])
{
if(!vis[to[i]])
{
md = deep[to[i]] = 1 , dis[to[i]] = len[i] , f[1] = len[i] , sf[1] = 1 , getdeep(to[i] , x);
for(j = 1 ; j <= md && j <= k ; j ++ )
{
if(ans < f[j] + g[k - j]) ans = f[j] + g[k - j] , num = sf[j] * sg[k - j];
else if(ans == f[j] + g[k - j])num += sf[j] * sg[k - j];
}
for(j = 1 ; j <= md && j <= k ; j ++ )
{
if(g[j] < f[j]) g[j] = f[j] , sg[j] = sf[j];
else if(g[j] == f[j]) sg[j] += sf[j];
}
for(j = 1 ; j <= md ; j ++ ) f[j] = -inf , sf[j] = 0;
sm = max(sm , md);
}
}
for(i = 1 ; i <= sm && i <= k ; i ++ ) g[i] = -inf , sg[i] = 0;
for(i = head[x] ; i ; i = next[i])
if(!vis[to[i]])
root = 0 , sum = si[to[i]] , getroot(to[i] , x) , query(root);
}
int main()
{
int m , i , x , y , z;
scanf("%d%d%d" , &n , &m , &k) , k -- ;
for(i = 1 ; i <= m ; i ++ ) scanf("%d%d%d" , &x , &y , &z) , aa(x , y , z) , aa(y , x , z);
dijkstra() , uu[1] = 1 , dfs(1);
memset(f , 0xc0 , sizeof(f)) , memset(g , 0xc0 , sizeof(g)) , g[0] = 0 , sg[0] = 1;
bs[0] = inf , sum = n , getroot(1 , 0) , query(root);
printf("%d %d\n" , ans , num);
return 0;
}
【bzoj4016】[FJOI2014]最短路径树问题 堆优化Dijkstra+DFS树+树的点分治的更多相关文章
- PAT-1030 Travel Plan (30 分) 最短路最小边权 堆优化dijkstra+DFS
PAT 1030 最短路最小边权 堆优化dijkstra+DFS 1030 Travel Plan (30 分) A traveler's map gives the distances betwee ...
- 【51nod1443】路径和树(堆优化dijkstra乱搞)
点此看题面 大致题意:给你一个无向联通图,要求你求出这张图中从u开始的权值和最小的最短路径树的权值之和. 什么是最短路径树? 从\(u\)开始到任意点的最短路径与在原图中相比不变. 题解 既然要求最短 ...
- [BZOJ4016][FJOI2014]最短路径树问题
[BZOJ4016][FJOI2014]最短路径树问题 试题描述 给一个包含n个点,m条边的无向连通图.从顶点1出发,往其余所有点分别走一次并返回. 往某一个点走时,选择总长度最短的路径走.若有多条长 ...
- 【bzoj3073】[Pa2011]Journeys 线段树优化建图+堆优化Dijkstra
题目描述 Seter建造了一个很大的星球,他准备建造N个国家和无数双向道路.N个国家很快建造好了,用1..N编号,但是他发现道路实在太多了,他要一条条建简直是不可能的!于是他以如下方式建造道路:(a, ...
- 洛谷 P3371 【模板】单源最短路径(堆优化dijkstra)
题目描述 如题,给出一个有向图,请输出从某一点出发到所有点的最短路径长度. 输入输出格式 输入格式: 第一行包含三个整数N.M.S,分别表示点的个数.有向边的个数.出发点的编号. 接下来M行每行包含三 ...
- 配对堆优化Dijkstra算法小记
关于配对堆的一些小姿势: 1.配对堆是一颗多叉树. 2.包含优先队列的所有功能,可用于优化Dijkstra算法. 3.属于可并堆,因此对于集合合并维护最值的问题很实用. 4.速度快于一般的堆结构(左偏 ...
- BZOJ 3040 最短路 (堆优化dijkstra)
这题不是裸的最短路么?但是一看数据范围就傻了.点数10^6,边数10^7.这个spfa就别想了(本来spfa就是相当不靠谱的玩意),看来是要用堆优化dijkstra了.但是,平时写dijkstra时为 ...
- BZOJ5415[Noi2018]归程——kruskal重构树+倍增+堆优化dijkstra
题目描述 本题的故事发生在魔力之都,在这里我们将为你介绍一些必要的设定. 魔力之都可以抽象成一个 n 个节点.m 条边的无向连通图(节点的编号从 1 至 n).我们依次用 l,a 描述一条边的长度.海 ...
- 堆优化Dijkstra计算最短路+路径计数
今天考试的时候遇到了一道题需要路径计数,然而蒟蒻从来没有做过,所以在考场上真的一脸懵逼.然后出题人NaVi_Awson说明天考试还会卡SPFA,吓得我赶紧又来学一波堆优化的Dijkstra(之前只会S ...
随机推荐
- 卓越管理的实践技巧(1)如何进行有效的指导 Guidelines for Effective Coaching
Guidelines for Effective Coaching 前文卓越管理的秘密(Behind Closed Doors)最后一部分提到了总结的13条卓越管理的实践技巧并列出了所有实践技巧名称的 ...
- Unity runtime性能分析器
一. Profiler: 1. CPU Usage A. WaitForTargetFPS: Vsync(垂直同步)功能所,即显示当前帧的CPU等待时间 B. Overhead: Profiler总体 ...
- [VC]关于ocx控件的自己编写的dll问题
要是无法删除c:windows/cownloadprogrames下的文件时可以关掉所有的浏览器,然后在internate----程序---管理 加载项里 先把那个加载项 更新一下,或者禁用一下,或者 ...
- .net代码获取节点以及读取属性
获取配置文件的节点,可以使用System.Configuration.ConfigurationManager.GetSection方法获取指定的节点,以sessionstate节点为例,如果需要获取 ...
- HDU 5091 Beam Cannon (扫描线思想)
题意:移动一个矩形,使矩形内包含的点尽量多. 思路:把一个点拆成两个事件,一个进(权值为1)一个出(权值为-1),将所有点按照x排序,然后扫描,对于每个x,用一个滑窗计算一下最大值,再移动扫描线.树状 ...
- Android(java)学习笔记116:BroadcastReceiver之 静态注册 和 动态注册
1. 广播接受者>什么是广播.收音机.电台:对外发送信号.收音机:接收电台的信号. >在android系统里面,系统有很多重要的事件: 电池电量低,插入充电器,sd卡被移除,有电话打出去, ...
- Hybrid App开发之Html基本标签使用
前言: 前面简单学习了html简单标签的使用,今天学习一下其他的标签的使用. HTML的超链接 1.)创建一个超链接 <div> <p> <a href="ht ...
- jQuery如何获取选中单选按钮radio的值
使用jquery获取radio的值,最重要的是掌握jquery选择器的使用,在一个表单中我们通常是要获取被选中的那个radio项的值,所以要加checked来筛选,比如有以下的一些radio项: 1. ...
- 最全面的 python 字符串拼接总结(带注释版)
在 Python 中字符串连接有多种方式,这里简单做个总结,应该是比较全面的了,方便以后查阅. 加号连接 第一种,通过+号的形式: >>> a, b = 'hello', ' wor ...
- Django 模板函数
Django 模板函数 在模板中的函数是只需要函数名,不用加括号,自动执行 在前端中的函数 不用加括号,函数自动执行 前端 {% for item in userinfo.keys %} <h3 ...