【BZOJ4016】【FJOI2014】最短路径树问题
题意:
Description
Input
Output
输出一行两个整数,以一个空格隔开,第一个整数表示包含K个点的路径最长为多长,第二个整数表示这样的不同的最长路径有多少条。
n<=30000,m<=60000,2<=K<=n
题解:
一眼题啊。。。SBFA写挂能怪谁QAQ
先把最小路径树建出来,然后就是点分治经典问题了;
关于最小路径树:
先以1为源点跑一边最短路,然后把对最短路没有贡献的边去掉,再按照字典序dfs一次把非树边去掉(有可能有多个最短路)即可。
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<queue>
#define inf 2147483647
#define eps 1e-9
using namespace std;
typedef long long ll;
struct edge{
int v,w,next;
}a[],_a[],__a[];
struct _edge{
int u,v,w;
friend bool operator <(_edge a,_edge b){
return a.u==b.u?a.v>b.v:a.u<b.u;
}
}e[];
int n,m,k,u,v,w,ans=,anss,rt,S,tot=,_tot=,__tot=,siz[],mx[],head[],_head[],__head[],f[],g[],_f[],_g[],dis[];
bool used[],vis[];
void add(int u,int v,int w){
a[++tot].v=v;
a[tot].w=w;
a[tot].next=head[u];
head[u]=tot;
}
void _add(int u,int v,int w){
_a[++_tot].v=v;
_a[_tot].w=w;
_a[_tot].next=_head[u];
_head[u]=_tot;
}
void __add(int u,int v,int w){
__a[++__tot].v=v;
__a[__tot].w=w;
__a[__tot].next=__head[u];
__head[u]=__tot;
}
void spfa(){
queue<int>q;
bool isin[];
memset(isin,,sizeof(isin));
q.push();
isin[]=true;
dis[]=;
while(!q.empty()){
int u=q.front();
q.pop();
isin[u]=false;
for(int tmp=_head[u];tmp!=-;tmp=_a[tmp].next){
int v=_a[tmp].v;
if(dis[v]>dis[u]+_a[tmp].w){
dis[v]=dis[u]+_a[tmp].w;
if(!isin[v]){
isin[v]=true;
q.push(v);
}
}
}
}
sort(e+,e+m*+);
for(int i=;i<=m*;i++){
if(dis[e[i].v]==dis[e[i].u]+e[i].w){
__add(e[i].u,e[i].v,e[i].w);
}
}
}
void build(int u){
used[u]=true;
for(int tmp=__head[u];tmp!=-;tmp=__a[tmp].next){
int v=__a[tmp].v,w=__a[tmp].w;
if(!used[v]){
//printf("%d %d %d\n",u,v,w);
add(u,v,w);
add(v,u,w);
build(v);
}
}
}
void dfsrt(int u,int fa){
siz[u]=;
mx[u]=;
for(int tmp=head[u];tmp!=-;tmp=a[tmp].next){
int v=a[tmp].v;
if(v!=fa&&!vis[v]){
dfsrt(v,u);
mx[u]=max(mx[u],siz[v]);
siz[u]+=siz[v];
}
}
mx[u]=max(mx[u],S-siz[u]);
if(mx[u]<mx[rt])rt=u;
}
void dfs(int u,int fa,int dpt,int ww){
if(dpt>k)return;
if(ww>_f[dpt]){
_f[dpt]=ww;
_g[dpt]=;
}else if(ww==_f[dpt]){
_g[dpt]++;
}
for(int tmp=head[u];tmp!=-;tmp=a[tmp].next){
int v=a[tmp].v;
if(v!=fa&&!vis[v]){
dfs(v,u,dpt+,ww+a[tmp].w);
}
}
}
void divide(int u){
f[]=,g[]=;
for(int i=;i<=k;i++)f[i]=g[i]=;
vis[u]=true;
for(int tmp=head[u];tmp!=-;tmp=a[tmp].next){
int v=a[tmp].v,w=a[tmp].w;
if(!vis[v]){
for(int i=;i<=k;i++)_f[i]=_g[i]=;
dfs(v,,,w);
for(int i=;i<=k;i++){
if(ans<f[k-i]+_f[i]){
ans=f[k-i]+_f[i];
anss=g[k-i]*_g[i];
}else if(ans==f[k-i]+_f[i]){
anss+=g[k-i]*_g[i];
}
}
for(int i=;i<=k;i++){
if(f[i]<_f[i]){
f[i]=_f[i];
g[i]=_g[i];
}else if(f[i]==_f[i]){
g[i]+=_g[i];
}
}
}
}
for(int tmp=head[u];tmp!=-;tmp=a[tmp].next){
int v=a[tmp].v;
if(!vis[v]){
rt=,S=siz[v];
dfsrt(v,);
divide(rt);
}
}
}
int main(){
memset(dis,0x3f,sizeof(dis));
memset(head,-,sizeof(head));
memset(_head,-,sizeof(_head));
memset(__head,-,sizeof(__head));
memset(used,,sizeof(used));
memset(vis,,sizeof(vis));
scanf("%d%d%d",&n,&m,&k);
k--;
for(int i=;i<=m;i++){
scanf("%d%d%d",&u,&v,&w);
_add(u,v,w);
_add(v,u,w);
e[i*-]=(_edge){u,v,w};
e[i*]=(_edge){v,u,w};
}
spfa();
build();
mx[rt=]=,S=n;
dfsrt(,);
divide(rt);
printf("%d %d",ans,anss);
return ;
}
PS:BZOJ数据极水,我写了SPFA+没判字典序都过了
【BZOJ4016】【FJOI2014】最短路径树问题的更多相关文章
- [BZOJ4016][FJOI2014]最短路径树问题
[BZOJ4016][FJOI2014]最短路径树问题 试题描述 给一个包含n个点,m条边的无向连通图.从顶点1出发,往其余所有点分别走一次并返回. 往某一个点走时,选择总长度最短的路径走.若有多条长 ...
- [BZOJ4016][FJOI2014]最短路径树问题(dijkstra+点分治)
4016: [FJOI2014]最短路径树问题 Time Limit: 5 Sec Memory Limit: 512 MBSubmit: 1796 Solved: 625[Submit][Sta ...
- 【BZOJ4016】[FJOI2014]最短路径树问题
[BZOJ4016][FJOI2014]最短路径树问题 题面 bzoj 洛谷 题解 虽然调了蛮久,但是思路还是蛮简单的2333 把最短路径树构出来,然后点分治就好啦 ps:如果树构萎了,这组数据可以卡 ...
- 【BZOJ4016】[FJOI2014]最短路径树问题 最短路径树+点分治
[BZOJ4016][FJOI2014]最短路径树问题 Description 给一个包含n个点,m条边的无向连通图.从顶点1出发,往其余所有点分别走一次并返回. 往某一个点走时,选择总长度最短的路径 ...
- 【BZOJ4016】[FJOI2014]最短路径树问题(点分治,最短路)
[BZOJ4016][FJOI2014]最短路径树问题(点分治,最短路) 题面 BZOJ 洛谷 题解 首先把最短路径树给构建出来,然后直接点分治就行了. 这个东西似乎也可以长链剖分,然而没有必要. # ...
- bzoj 4016 [FJOI2014]最短路径树问题(最短路径树+树分治)
4016: [FJOI2014]最短路径树问题 Time Limit: 5 Sec Memory Limit: 512 MBSubmit: 426 Solved: 147[Submit][Stat ...
- BZOJ_4016_[FJOI2014]最短路径树问题_最短路+点分治
BZOJ_4016_[FJOI2014]最短路径树问题_最短路+点分治 Description 给一个包含n个点,m条边的无向连通图.从顶点1出发,往其余所有点分别走一次并返回. 往某一个点走时,选择 ...
- 【BZOJ-4016】最短路径树问题 Dijkstra + 点分治
4016: [FJOI2014]最短路径树问题 Time Limit: 5 Sec Memory Limit: 512 MBSubmit: 1092 Solved: 383[Submit][Sta ...
- [FJOI2014]最短路径树问题 长链剖分
[FJOI2014]最短路径树问题 LG传送门 B站传送门 长链剖分练手好题. 如果你还不会长链剖分的基本操作,可以看看我的总结. 这题本来出的很没水平,就是dijkstra(反正我是不用SPFA)的 ...
- 洛谷 [FJOI2014]最短路径树问题 解题报告
[FJOI2014]最短路径树问题 题目描述 给一个包含\(n\)个点,\(m\)条边的无向连通图.从顶点\(1\)出发,往其余所有点分别走一次并返回. 往某一个点走时,选择总长度最短的路径走.若有多 ...
随机推荐
- thinkphp5 模板中截取中文字符串
TP5模板页截取中文字符串 {$vo.task_detail|mb_substr=###,0,15,'utf-8'}
- mmap详解
共享内存可以说是最有用的进程间通信方式,也是最快的IPC形式, 因为进程可以直接读写内存,而不需要任何 数据的拷贝.对于像管道和消息队列等通信方式,则需要在内核和用户空间进行四次的数据拷贝,而共享内存 ...
- ansible 连通测试
[root@ftp:/root] > ansible ansible01 -m ping ansible01 | UNREACHABLE! => { "changed" ...
- 引入拦截器及swagger支持及解决redis无法初始化问题
Springboot引入拦截器 自定义的拦截器类 Interceptor package cn.zytao.taosir.auth.config; import javax.annotation.Re ...
- Vue 实现前进刷新,后退不刷新的效果
需求一: 在一个列表页中,第一次进入的时候,请求获取数据.点击某个列表项,跳到详情页,再从详情页后退回到列表页时,不刷新.也就是说从其他页面进到列表页,需要刷新获取数据,从详情页返回到列表页时不要刷新 ...
- [using_microsoft_infopath_2010]Chapter6 发布提交表单数据
本章概要: 1.使用正确的方法发布表单 2.发布表单画库到SharePoint 3.在发布和保存表单之间做出选择 4.理解不同发布表单方式之间的区别
- [AngularJS]Chapter 5 与服务器交互
第八章有关于缓存的东西. [通过$http交互] 传统的AJAX请求如下 var xmlhttp = new XMLHttpRequest(); xmlhttp.onreadystatechange ...
- gdb学习-checkpoint,watch
checkpoint的内容参考: http://blog.chinaunix.net/uid-23629988-id-2943273.html 这一篇主要是checkpoint,在next之前加che ...
- npm API文档
npm API文档 https://docs.npmjs.com/
- 从零開始学android<TabHost标签组件.二十九.>
TabHost主要特点是能够在一个窗体中显示多组标签栏的内容,在Android系统之中每一个标签栏就称为一个Tab.而包括这多个标签栏的容器就将其称为TabHost.TabHost类的继承结构例如以下 ...