HYSBZ - 4016 最短路径树问题 点分治 + 最短路径最小字典序
题解:首先对于给定的图,需要找到那些从1好点出发然后到x号点的最短路, 如果有多条最短路就要找到字典序最小的路,这样扣完这些边之后就会有一棵树。然后再就是很普通的点分治了。
对于扣边这个问题, 我们先跑一遍最短路,这样就可以得到1号点到其他的点的距离。
然后在跑一遍dfs, 我们在跑dfs找路的时候, 可以通过 d[u] + ct[i] == d[v] 来判断是不是最短路是否可以走这条边, 然后我们再从所有可能边中的最小编号出发,这样我们就能保证字典序最小了。
代码:
#include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define lch(x) tr[x].son[0]
#define rch(x) tr[x].son[1]
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL mod = (int)1e9+;
const int N = 3e4 + ;
vector<pll> vc[N];
int d[N];
void dij(){
memset(d, inf, sizeof(d));
priority_queue<pll, vector<pll>, greater<pll> > q;
d[] = ;
q.push(pll(,));
int x, dd, v, ct;
while(!q.empty()){
x = q.top().se, dd = q.top().fi;
q.pop();
if(dd != d[x]) continue;
for(int i = ; i < vc[x].size(); ++i){
v = vc[x][i].fi , ct = vc[x][i].se;
if(d[v] > d[x] + ct){
d[v] = d[x] + ct;
q.push(pll(d[v], v));
}
}
}
return;
}
int vis[N];
int head[N], to[N<<], val[N<<], nt[N<<], tot = ;
void add(int u, int v, int ct){
to[tot] = v;
val[tot] = ct;
nt[tot] = head[u];
head[u] = tot++;
return ;
}
void dfs(int u){
vis[u] = ;
int v, dd;
for(int i = ; i < vc[u].size(); i++){
v = vc[u][i].fi, dd = vc[u][i].se;
if(vis[v] || d[v] != d[u] + dd) continue;
add(u, v, dd);
add(v, u, dd);
dfs(v);
}
return ;
}
int sz[N];
int rt, minval;
int n, m, k;
void get_rt(int o, int u, int num){
sz[u] = ;
int v;
int maxval = ;
for(int i = head[u]; ~i; i = nt[i]){
v = to[i];
if(v == o || vis[v]) continue;
get_rt(u, v, num);
sz[u] += sz[v];
maxval = max(maxval, sz[v]);
}
if(o) maxval = max(maxval, num - sz[u]);
if(maxval < minval){
minval = maxval;
rt = u;
}
}
int fans = , fcnt = ;
int cnt[N], dis[N];
void Update(int vval, int num){
if(fans == vval) fcnt += num;
else if(fans < vval) fans = vval, fcnt = num;
return ;
}
void Dfs(int o, int u, int w, int num){
sz[u] = ;
if(num == k-)
Update(w, );
if(k >= num && dis[k-num]){
Update(w+dis[k-num], cnt[k-num]);
}
for(int i = head[u]; ~i; i = nt[i]){
int v = to[i];
if(v == o || vis[v]) continue;
Dfs(u, v,w+val[i], num+);
sz[u] += sz[v];
}
return ;
}
void Change(int o, int u, int w, int num, int op){
if(num >= k) return ;
if(op == ) {
if(dis[num+] < w) dis[num+] = w, cnt[num+] = ;
else if(dis[num+] == w) cnt[num+]++;
}
else dis[num+] = cnt[num+] = ;
for(int i = head[u]; ~i; i = nt[i]){
int v = to[i];
if(v == o || vis[v]) continue;
Change(u, v, w+val[i], num+, op);
}
return ;
}
void solve(int x, int num){
if(num <= ) return ;
minval = inf;
get_rt(, x, num);
vis[rt] = ;
int v;
for(int i = head[rt]; ~i; i = nt[i]){
v = to[i];
if(vis[v]) continue;
Dfs(, v, val[i], );
Change(, v, val[i], , );
}
for(int i = head[rt]; ~i; i = nt[i]){
v = to[i];
if(vis[v]) continue;
Change(, v, val[i], , );
}
for(int i = head[rt]; ~i; i = nt[i]){
v = to[i];
if(vis[v]) continue;
solve(v, sz[v]);
}
return ;
}
int main(){
int u, v, w;
memset(head, -, sizeof(head));
scanf("%d%d%d", &n, &m, &k);
for(int i = ; i <= m; i++){
scanf("%d%d%d", &u, &v, &w);
vc[u].pb(pll(v,w));
vc[v].pb(pll(u,w));
}
dij();
dfs();
memset(vis, , sizeof(vis));
solve(, n);
printf("%d %d", fans, fcnt);
return ;
}
HYSBZ - 4016 最短路径树问题 点分治 + 最短路径最小字典序的更多相关文章
- BZOJ 4016 最短路径树问题 最短路径树构造+点分治
题目: BZOJ4016最短路径树问题 分析: 大家都说这是一道强行拼出来的题,属于是两种算法的模板题. 我们用dijkstra算法算出1为源点的最短路数组,然后遍历一下建出最短路树. 之后就是裸的点 ...
- P2993 [FJOI2014]最短路径树问题 点分治+最短路
这道题还是非常简单的,由于我们要保证最小字典序,因此我们需要把边进行排序,然后从大到小插入,因为链式前向星是倒着存的.我们只需要先跑一个最短路,然后查询边是不是在最短路上,这个可以通过枚举边并用 di ...
- 【bzoj4016】[FJOI2014]最短路径树问题 堆优化Dijkstra+DFS树+树的点分治
题目描述 给一个包含n个点,m条边的无向连通图.从顶点1出发,往其余所有点分别走一次并返回. 往某一个点走时,选择总长度最短的路径走.若有多条长度最短的路径,则选择经过的顶点序列字典序最小的那条路径( ...
- bzoj 4016 [FJOI2014]最短路径树问题(最短路径树+树分治)
4016: [FJOI2014]最短路径树问题 Time Limit: 5 Sec Memory Limit: 512 MBSubmit: 426 Solved: 147[Submit][Stat ...
- 【BZOJ-4016】最短路径树问题 Dijkstra + 点分治
4016: [FJOI2014]最短路径树问题 Time Limit: 5 Sec Memory Limit: 512 MBSubmit: 1092 Solved: 383[Submit][Sta ...
- [BZOJ4016][FJOI2014]最短路径树问题(dijkstra+点分治)
4016: [FJOI2014]最短路径树问题 Time Limit: 5 Sec Memory Limit: 512 MBSubmit: 1796 Solved: 625[Submit][Sta ...
- bzoj 4016: [FJOI2014]最短路径树问题
bzoj4016 最短路路径问题 Time Limit: 5 Sec Memory Limit: 512 MB Description 给一个包含n个点,m条边的无向连通图.从顶点1出发,往其余所有点 ...
- HDU4871 Shortest-path tree(最短路径树 + 树的点分治)
题目大概要先求一张边有权的图的根为1的最短路径树,要满足根到各点路径序列的字典序最小:然后求这棵最短路径树包含k个结点的最长路径的长度和个数. 首先先构造出这棵字典序最小的最短路径树..好吧,我太傻逼 ...
- BZOJ_4016_[FJOI2014]最短路径树问题_最短路+点分治
BZOJ_4016_[FJOI2014]最短路径树问题_最短路+点分治 Description 给一个包含n个点,m条边的无向连通图.从顶点1出发,往其余所有点分别走一次并返回. 往某一个点走时,选择 ...
随机推荐
- 第四章-使用本机文件对话框和帮助进程间沟通 | Electron实战
本章主要内容: 使用Electron的dialog模块实现一个本机打开文件对话框 促进主进程和渲染器进程之间的通信 将功能从主进程暴露给渲染器进程 使用Electron的remote模块从主进程导入功 ...
- Spring的依赖注入和管理Bean
采用Spring管理Bean和依赖注入 1.实例化spring容器 和 从容器获取Bean对象 实例化Spring容器常用的两种方式: 方法一: 在类路径下寻找配置文件来实例化容器 [推荐使用] Ap ...
- 1和new Number(1)有什么区别
1和new Number(1)有什么区别 author: @Tiffanysbear 总结,两者的区别就是原始类型和包装对象的区别. 什么是包装对象 对象Number.String.Boolean分别 ...
- 并发编程(3)——ThreadPoolExecutor
ThreadPoolExecutor 1. ctl(control state) 线程池控制状态,包含两个概念字段:workerCount(线程有效数量)和runState(表示是否在运行.关闭等状态 ...
- 数据结构之最小堆的实现C++版
完全二叉树之所以用数组的方式存在,在于他的一个特性 若子节点为i,则父节点为(i-1)/2,注意c++特性,该结果肯定是个整数. 若父节点为j,则子节点必为2*j+1;则在数组里面可以非常方便的通过下 ...
- postman->newman->jenkins构建过程的问题记录及解决方法
从postman导出请求集合后要做的工作: 需要调整导出的json文件,如配置环境变量{{host}},需要修改成准确的url; 通过newman执行newman run test_request.j ...
- 防抖(debounce)和节流(throttle)
场景说明:一般我们在前端页面中会给元素绑定click.scroll.onmousemove.resize等事件,这些事件的执行函数如果是去发请求获取数据的话,我们无意识的连续点击或者连续滚动会给服务器 ...
- RecyclerView实现混合布局
PS:好长时间不写博客了,起初是不知道写些什么,后来接触了到了很多东西,原本看似简单的东西,背后都隐藏着巨大的秘密,想handler的使用,一般情况下会引起内存泄漏问题,想着找到方法结局不就得了吗,可 ...
- spring事务在实际项目开发中的使用
一, 事务的一些基础知识简单回顾一下,讲的不是很深入,网上博客很多. 1,关于事务的四大特性:原子性.隔离性.一致性.隔离性 本文不再赘述: 2,事务的隔离级别:读未提交,读已提交,可重复读,串行 ...
- 微服务架构 - 网关 Spring Cloud Gateway
Spring Cloud Gateway 工作原理 客户端向 Spring Cloud Gateway 发出请求,如果请求与网关程序定义的路由匹配,则将其发送到网关 Web 处理程序,此处理程序运行特 ...