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

Time Limit: 5 Sec  Memory Limit: 512 MB
Submit: 426  Solved: 147
[Submit][Status][Discuss]

Description

给一个包含n个点,m条边的无向连通图。从顶点1出发,往其余所有点分别走一次并返回。
往某一个点走时,选择总长度最短的路径走。若有多条长度最短的路径,则选择经过的顶点序列字典序最小的那条路径(如路径A为1,32,11,路
径B为1,3,2,11,路径B字典序较小。注意是序列的字典序的最小,而非路径中节点编号相连的字符串字典序最小)。到达该点后按原路返回,然后往其他
点走,直到所有点都走过。
可以知道,经过的边会构成一棵最短路径树。请问,在这棵最短路径树上,最长的包含K个点的简单路径长度为多长?长度为该最长长度的不同路径有多少条?
这里的简单路径是指:对于一个点最多只经过一次的路径。不同路径是指路径两端端点至少有一个不同,点A到点B的路径和点B到点A视为同一条路径。

Input

第一行输入三个正整数n,m,K,表示有
n个点m条边,要求的路径需要经过K个点。接下来输入m行,每行三个正整数Ai,Bi,Ci(1<=Ai,Bi<=n,1<=Ci&
lt;=10000),表示Ai和Bi间有一条长度为Ci的边。数据保证输入的是连通的无向图。
 
 

Output

输出一行两个整数,以一个空格隔开,第一个整数表示包含K个点的路径最长为多长,第二个整数表示这样的不同的最长路径有多少条。
 

Sample Input

6 6 4
1 2 1
2 3 1
3 4 1
2 5 1
3 6 1
5 6 1

Sample Output

3 4

HINT

对于所有数据n<=30000,m<=60000,2<=K<=n。数据保证最短路径树上至少存在一条长度为K的路径。

【思路】

先求出满足要求的最短路树来。

分治:求出过根节点的点对数,其它递归处理。

求过根节点的点对:假设现在处理根节点的S子树,用f[i][0]表示前S-1棵子树中与根相距i个节点(不含根)的最长路径,f[i][1]表示方案数,类似的定义tmp为当前S子树的统计结果。一遍bfs构造出tmp,枚举该子树上的结点数更新答案,然后用tmp更新f。

需要注意的有:

累计答案的诸多小细节。

f[][],tmp[][],queue的清零。

【代码】

 #include<cstdio>
#include<vector>
#include<queue>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std; const int N = +;
const int INF = 1e9+1e9; struct Edge {
int v,w;
Edge(int v=,int w=):v(v),w(w) {}
bool operator < (const Edge& rhs) const {
return v<rhs.v;
}
};
queue<int> q;
int n,m,K,root,size,d[N],inq[N];
int ans1,ans2,siz[N],mx[N],vis[N],dep[N],dis[N],fa[N];
vector<Edge> g[N],G[N]; void spfa() {
for(int i=;i<=n;i++) d[i]=INF;
memset(inq,,sizeof(inq));
inq[]=; q.push();
while(!q.empty()) {
int u=q.front(); q.pop(); inq[u]=;
for(int i=;i<g[u].size();i++) {
int v=g[u][i].v,w=g[u][i].w;
if(d[v]>d[u]+w) {
d[v]=d[u]+w;
if(!inq[v]) inq[v]=,q.push(v);
}
}
}
}
void dfs(int u) {
vis[u]=;
for(int i=;i<g[u].size();i++) {
int v=g[u][i].v,w=g[u][i].w;
if(!vis[v] && d[v]==d[u]+w) {
G[u].push_back(Edge(v,w));
G[v].push_back(Edge(u,w));
dfs(v);
}
}
}
void getroot(int u) {
siz[u]=; mx[u]=;
for(int i=;i<G[u].size();i++) {
int v=G[u][i].v;
if(v!=fa[u] && !vis[v]) {
fa[v]=u;
getroot(v);
siz[u]+=siz[v];
if(siz[v]>mx[u]) mx[u]=siz[v];
}
}
mx[u]=max(mx[u],size-siz[u]);
if(mx[u]<mx[root]) root=u;
}
int f[N][],tmp[N][];
void solve(int u,int S){
vis[u]=; f[][]=;
int m=G[u].size();
for(int i=;i<m;i++) {
int v=G[u][i].v;
if(!vis[v]) {
while(!q.empty()) q.pop(); //clear
q.push(v),dep[v]=,dis[v]=G[u][i].w,fa[v]=u;
while(!q.empty()) {
int now=q.front(); q.pop();
int k=dep[now];
if(k>K) break;
if(dis[now]>tmp[k][])
tmp[k][]=dis[now],tmp[k][]=;
if(dis[now]==tmp[k][]) tmp[k][]++;
for(int j=;j<G[now].size();j++) {
int to=G[now][j].v;
if(!vis[to] && to!=fa[now]) {
fa[to]=now;
dep[to]=dep[now]+;
dis[to]=dis[now]+G[now][j].w;
q.push(to);
}
}
}
//for(int j=1;j<=K;j++) printf("(%d,%d) ",tmp[j][0],tmp[j][1]);cout<<endl;
for(int j=;j<=K;j++) { //tmp位于前可以取[1..K]
if(tmp[j][]+f[K-j][]>ans1)
ans1=tmp[j][]+f[K-j][],ans2=;
if(tmp[j][]+f[K-j][]==ans1)
ans2+=tmp[j][]*f[K-j][];
}
for(int j=;j<=K;j++) {
if(tmp[j][]>f[j][]) f[j][]=tmp[j][],f[j][]=;
if(tmp[j][]==f[j][]) f[j][]+=tmp[j][];
tmp[j][]=tmp[j][]=;
}
}
}
//cout<<u<<": "<<ans1<<" "<<ans2<<endl;
for(int j=;j<=K;j++) f[j][]=f[j][]=;
m=G[u].size();
for(int i=;i<m;i++) {
int v=G[u][i].v;
if(!vis[v]) {
size=siz[v];
if(siz[v]>siz[u]) siz[v]=S-siz[v];
root=;
if(size>=K) getroot(v);
solve(root,siz[v]);
}
}
}
void read(int& x) {
char c=getchar(); int f=; x=;
while(!isdigit(c)){if(c=='-') f=-;c=getchar();}
while(isdigit(c)) x=x*+c-'',c=getchar();
x*=f;
}
int main() {
//freopen("in.in","r",stdin);
//freopen("out.out","w",stdout);
read(n),read(m),read(K); K--;
int u,v,w;
for(int i=;i<m;i++) {
read(u),read(v),read(w);
g[u].push_back(Edge(v,w));
g[v].push_back(Edge(u,w));
}
for(int i=;i<=n;i++)
sort(g[i].begin(),g[i].end());
spfa();
memset(vis,,sizeof(vis));
dfs();
size=n; mx[]=INF; root=;
memset(vis,,sizeof(vis));
getroot() , solve(root,size);
printf("%d %d",ans1,ans2);
return ;
}

bzoj 4016 [FJOI2014]最短路径树问题(最短路径树+树分治)的更多相关文章

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

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

  2. BZOJ 4016: [FJOI2014]最短路径树问题( 最短路 + 点分治 )

    先跑出最短路的图, 然后对于每个点按照序号从小到大访问孩子, 就可以搞出符合题目的树了. 然后就是经典的点分治做法了. 时间复杂度O(M log N + N log N) -------------- ...

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

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

  4. Bzoj4016/洛谷P2993 [FJOI2014] 最短路径树问题(最短路径问题+长链剖分/点分治)

    题面 Bzoj 洛谷 题解 首先把最短路径树建出来(用\(Dijkstra\),没试过\(SPFA\)\(\leftarrow\)它死了),然后问题就变成了一个关于深度的问题,可以用长链剖分做,所以我 ...

  5. “中兴捧月”比赛之——二叉查找树(BST)树的最短路径Java求解

    问题描述: BST树,又称二叉查找树,求其到所有叶子节点路径的最小值 测试用例一:  10 5 20 返回15: 测试用例二: 100 20 70 110 120 10 null null 89 nu ...

  6. 经典树与图论(最小生成树、哈夫曼树、最短路径问题---Dijkstra算法)

    参考网址: https://www.jianshu.com/p/cb5af6b5096d 算法导论--最小生成树 最小生成树:在连通网的所有生成树中,所有边的代价和最小的生成树,称为最小生成树. im ...

  7. [BZOJ 1576] [Usaco2009 Jan] 安全路经Travel 【树链剖分】

    题目链接: BZOJ - 1576 题目分析 首先Orz Hzwer的题解. 先使用 dijikstra 求出最短路径树. 那么对于一条不在最短路径树上的边 (u -> v, w) 我们可以先沿 ...

  8. bzoj 1576 [Usaco2009 Jan]安全路经Travel(树链剖分,线段树)

    [题意] 给定一个无向图,找到1-i所有的次短路经,要求与最短路径的最后一条边不重叠. [思路] 首先用dijkstra算法构造以1为根的最短路树. 将一条无向边看作两条有向边,考察一条不在最短路树上 ...

  9. 主席树||可持久化线段树+离散化 || 莫队+分块 ||BZOJ 3585: mex || Luogu P4137 Rmq Problem / mex

    题面:Rmq Problem / mex 题解: 先离散化,然后插一堆空白,大体就是如果(对于以a.data<b.data排序后的A)A[i-1].data+1!=A[i].data,则插一个空 ...

随机推荐

  1. mysql主从 1050错误

    在mysql从库上查询时出现如下错误 ...................... Last_Errno: 1050                    Last_Error: Error 'Tab ...

  2. 读取xml文件(可执行文件根目录debug)

    xml文件格式如下 <?xml version="1.0" encoding="utf-8" ?> <root> <appKey& ...

  3. linux中C的静态库和动态库分析

    从开始学C语言写第一个"hello world"历程到现在,我依然困惑于到底这个程序完整的执行流程是什么样的.不过,现在我正在尝试一点一点的揭开它的面纱.现在,我尝试分析linux ...

  4. dustjs

    http://akdubya.github.io/dustjs/ https://github.com/linkedin/dustjs

  5. Mac双系统切换

    苹果系统和WIN7系统  切换和使用说明 先按住“alt(opfion)”不放手,然后在按开机键,会进入选择页面,选择win8 会进入 windos页面 ,选择MACintos h HD(Mac)会进 ...

  6. C# string LastIndexOf()

    IndexOf(“FindText",start,len) 中的Start和Len是从左往右数的 LastIndexOf(“FindText",start,len)中的则是从右往左 ...

  7. 修改.htaccess实现子目录绑定示例分享

    <IfModule mod_rewrite.c>RewriteEngine On  RewriteBase /# 把 www.jb51.net改为你要绑定的域名.# 如果是域名:Rewri ...

  8. [原博客] POI系列(5)

    正规.严谨.精妙. -POI BZOJ 2213 : [Poi2011]Difference 如果我们每次枚举两个字母最大最小情况时,很容易想到写出代码里注释的样子.这样是26*26*n的,我们发现枚 ...

  9. [原博客] HEOI2014 行记

    HEOI: 河北省信息学竞赛省队选拔赛 HEOI数据标程下载 百度盘 http://pan.baidu.com/s/1qWx7YAo 又到了一年一度的HEOI呢. 我果然还是太弱了呢. Day0 报到 ...

  10. Druid :大数据实时处理的开源分布式系统(1)

    引言 Druid 是一个快速,近实时的查询海量只读数据的系统.Druid 的目标是可用性要达到100%,即使在部署新代码,或者某些节点 down 机的情况下. Druid 目前支持的单表查询方式和 D ...