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出发,往其余所有点分别走一次并返回. 往某一个点走时,选择 ...
随机推荐
- Linux服务部署Yapi项目(安装Node Mongdb Git Nginx等)
Linux服务部署Yapi 一,介绍与需求 1,我的安装环境:CentOS7+Node10.13.0+MongoDB4.0.10. 2,首先安装wget,用于下载node等其他工具 yum insta ...
- Java泛型使用的简单介绍
目录 一. 泛型是什么 二. 使用泛型有什么好处 三. 泛型类 四. 泛型接口 五. 泛型方法 六. 限定类型变量 七. 泛型通配符 7.1 上界通配符 7.2 下界通配符 7.3 无限定通配符 八. ...
- zookeeper基本知识入门(一)
之前我们在搭建hadoop分布式环境的时候用到过Zookeeper注册hadoop服务.那么到底Zookeeper在分布式环境中发挥了什么作用呢,这次我们就来讨论这个问题. 在分布式系统中通常都会有多 ...
- HTML/CSS:导航栏水平和垂直
1.垂直导航栏 导航栏 = 链接列表导航栏基本上是一个链接列表,因此使用 <ul> 和 <li> 元素是非常合适的.如需构建垂直导航栏,我们只需要定义 <a> 元素 ...
- [转载]使用Java操作Mongodb
HelloWorld程序 学习任何程序的第一步,都是编写HelloWorld程序,我们也不例外,看下如何通过Java编写一个HelloWorld的程序. 首先,要通过Java操作Mongodb,必须先 ...
- 【CodeForces - 1200A】Hotelier(水题、模拟)
Hotelier 直接翻译了 Descriptions Amugae的酒店由10人组成10客房.房间从0开始编号0到99 从左到右. 酒店有两个入口 - 一个来自左端,另一个来自右端.当顾客通过左入口 ...
- Ubuntu : apt-get 命令
apt-get 命令是 Ubuntu 系统中的包管理工具,可以用来安装.卸载包,也可以用来升级包,还可以用来把系统升级到新的版本.本文介绍 apt-get 命令的基本用法,演示环境为 Ubuntu 1 ...
- 带你剖析WebGis的世界奥秘----点和线的世界
前言 昨天写了好久的博文我没保存,今天在来想继续写居然没了,气死人啊这种情况你们见到过没,所以今天重新写,我还是切换到了HTML格式的书写上.废话不多说了,我们现在就进入主题,上周我仔细研究了WebG ...
- MySQL-EXPLAIN执行计划Extra解释
EXPLAIN命令输出的列中Extra字段可选值较多,这里单独说一下. 该Extra列 EXPLAIN输出包含MySQL解决查询的额外信息.以下列表说明了此列中可能出现的值.每个项目还指示JSON格式 ...
- java读取本机磁盘及遍历磁盘文件
1. 获取本机所有盘符信息 //1. 获取本机盘符 File[] roots = File.listRoots(); for (int i = 0; i < roots.length; i++) ...