bzoj 4016 [FJOI2014]最短路径树问题(最短路径树+树分治)
4016: [FJOI2014]最短路径树问题
Time Limit: 5 Sec Memory Limit: 512 MB
Submit: 426 Solved: 147
[Submit][Status][Discuss]
Description
径B为1,3,2,11,路径B字典序较小。注意是序列的字典序的最小,而非路径中节点编号相连的字符串字典序最小)。到达该点后按原路返回,然后往其他
点走,直到所有点都走过。
Input
n个点m条边,要求的路径需要经过K个点。接下来输入m行,每行三个正整数Ai,Bi,Ci(1<=Ai,Bi<=n,1<=Ci&
lt;=10000),表示Ai和Bi间有一条长度为Ci的边。数据保证输入的是连通的无向图。
Output
Sample Input
1 2 1
2 3 1
3 4 1
2 5 1
3 6 1
5 6 1
Sample Output
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]最短路径树问题(最短路径树+树分治)的更多相关文章
- bzoj 4016: [FJOI2014]最短路径树问题
bzoj4016 最短路路径问题 Time Limit: 5 Sec Memory Limit: 512 MB Description 给一个包含n个点,m条边的无向连通图.从顶点1出发,往其余所有点 ...
- BZOJ 4016: [FJOI2014]最短路径树问题( 最短路 + 点分治 )
先跑出最短路的图, 然后对于每个点按照序号从小到大访问孩子, 就可以搞出符合题目的树了. 然后就是经典的点分治做法了. 时间复杂度O(M log N + N log N) -------------- ...
- BZOJ 4016 [FJOI2014]最短路径树问题 (贪心+点分治)
题目大意:略 传送门 硬是把两个题拼到了一起= = $dijkstra$搜出单源最短路,然后$dfs$建树,如果$dis_{v}=dis_{u}+e.val$,说明这条边在最短路图内,然后像$NOIP ...
- Bzoj4016/洛谷P2993 [FJOI2014] 最短路径树问题(最短路径问题+长链剖分/点分治)
题面 Bzoj 洛谷 题解 首先把最短路径树建出来(用\(Dijkstra\),没试过\(SPFA\)\(\leftarrow\)它死了),然后问题就变成了一个关于深度的问题,可以用长链剖分做,所以我 ...
- “中兴捧月”比赛之——二叉查找树(BST)树的最短路径Java求解
问题描述: BST树,又称二叉查找树,求其到所有叶子节点路径的最小值 测试用例一: 10 5 20 返回15: 测试用例二: 100 20 70 110 120 10 null null 89 nu ...
- 经典树与图论(最小生成树、哈夫曼树、最短路径问题---Dijkstra算法)
参考网址: https://www.jianshu.com/p/cb5af6b5096d 算法导论--最小生成树 最小生成树:在连通网的所有生成树中,所有边的代价和最小的生成树,称为最小生成树. im ...
- [BZOJ 1576] [Usaco2009 Jan] 安全路经Travel 【树链剖分】
题目链接: BZOJ - 1576 题目分析 首先Orz Hzwer的题解. 先使用 dijikstra 求出最短路径树. 那么对于一条不在最短路径树上的边 (u -> v, w) 我们可以先沿 ...
- bzoj 1576 [Usaco2009 Jan]安全路经Travel(树链剖分,线段树)
[题意] 给定一个无向图,找到1-i所有的次短路经,要求与最短路径的最后一条边不重叠. [思路] 首先用dijkstra算法构造以1为根的最短路树. 将一条无向边看作两条有向边,考察一条不在最短路树上 ...
- 主席树||可持久化线段树+离散化 || 莫队+分块 ||BZOJ 3585: mex || Luogu P4137 Rmq Problem / mex
题面:Rmq Problem / mex 题解: 先离散化,然后插一堆空白,大体就是如果(对于以a.data<b.data排序后的A)A[i-1].data+1!=A[i].data,则插一个空 ...
随机推荐
- mysql主从 1050错误
在mysql从库上查询时出现如下错误 ...................... Last_Errno: 1050 Last_Error: Error 'Tab ...
- 读取xml文件(可执行文件根目录debug)
xml文件格式如下 <?xml version="1.0" encoding="utf-8" ?> <root> <appKey& ...
- linux中C的静态库和动态库分析
从开始学C语言写第一个"hello world"历程到现在,我依然困惑于到底这个程序完整的执行流程是什么样的.不过,现在我正在尝试一点一点的揭开它的面纱.现在,我尝试分析linux ...
- dustjs
http://akdubya.github.io/dustjs/ https://github.com/linkedin/dustjs
- Mac双系统切换
苹果系统和WIN7系统 切换和使用说明 先按住“alt(opfion)”不放手,然后在按开机键,会进入选择页面,选择win8 会进入 windos页面 ,选择MACintos h HD(Mac)会进 ...
- C# string LastIndexOf()
IndexOf(“FindText",start,len) 中的Start和Len是从左往右数的 LastIndexOf(“FindText",start,len)中的则是从右往左 ...
- 修改.htaccess实现子目录绑定示例分享
<IfModule mod_rewrite.c>RewriteEngine On RewriteBase /# 把 www.jb51.net改为你要绑定的域名.# 如果是域名:Rewri ...
- [原博客] POI系列(5)
正规.严谨.精妙. -POI BZOJ 2213 : [Poi2011]Difference 如果我们每次枚举两个字母最大最小情况时,很容易想到写出代码里注释的样子.这样是26*26*n的,我们发现枚 ...
- [原博客] HEOI2014 行记
HEOI: 河北省信息学竞赛省队选拔赛 HEOI数据标程下载 百度盘 http://pan.baidu.com/s/1qWx7YAo 又到了一年一度的HEOI呢. 我果然还是太弱了呢. Day0 报到 ...
- Druid :大数据实时处理的开源分布式系统(1)
引言 Druid 是一个快速,近实时的查询海量只读数据的系统.Druid 的目标是可用性要达到100%,即使在部署新代码,或者某些节点 down 机的情况下. Druid 目前支持的单表查询方式和 D ...