您的位置:首页 > 其它

BZOJ_4016_[FJOI2014]最短路径树问题_最短路+点分治

2018-05-20 07:54 423 查看

BZOJ_4016_[FJOI2014]最短路径树问题_最短路+点分治

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<=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 首先要理解题中‘字典序最小的含义’。 跑一边dij,对每个点开vector,如果更新前dis[to]==dis[x]+val[i]说明这条反边在最短路图上,就把这条反边加入to的vector中。 于是我们就有了一个最短路图,对每个vector进行排序,然后求出整个图的dfs树就是题中所求的最短路树。 然后就是一个点分治可做的问题了。 维护出当前深度下最长路径和最长路径的条数即可。   代码:
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <stdlib.h>
#include <vector>
#include <ext/pb_ds/priority_queue.hpp>
using namespace std;
using namespace __gnu_pbds;
#define N 30050
#define M 60050
#define RR register
inline char nc() {
static char buf[100000],*p1,*p2;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int rd() {
register int x=0;
register char s=nc();
while(s<'0'||s>'9') s=nc();
while(s>='0'&&s<='9') x=(x<<3)+(x<<1)+s-'0',s=nc();
return x;
}
int n,m,vis
,dis
,dfn
,K;
__gnu_pbds::priority_queue<pair<int,int> >q;
vector<int>v
;
int head
,to[M<<1],nxt[M<<1],val[M<<1],cnt=1;
__attribute__((optimize("-O2")))void add(int u,int v,int w) {
to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; val[cnt]=w;
}
__attribute__((optimize("-O2")))void dij() {
memset(dis,0x3f,sizeof(dis));
dis[1]=0; q.push(make_pair(0,1));
while(!q.empty()) {
RR int x=q.top().second,i; q.pop();
if(vis[x]) continue;
vis[x]=1;
for(i=head[x];i;i=nxt[i]) {
if(dis[to[i]]+val[i]==dis[x]) {
// puts("FUCK");
v[to[i]].push_back(i^1);
}
}
for(i=head[x];i;i=nxt[i]) {
if(dis[to[i]]>dis[x]+val[i]) {
dis[to[i]]=dis[x]+val[i];
q.push(make_pair(-dis[to[i]],to[i]));
}
}
}
}
__attribute__((optimize("-O2")))inline bool cmp(int x,int y) {return to[x]<to[y];}
struct Fenzhi {
int head
,to[M<<1],nxt[M<<1],val[M<<1],cnt,used
,sum,ans,tot;
int f
,siz
,root,d
,dep
,maxdep,maxmaxdep;
int g
,h
,t1
,t2
;//g[i]表示深度为i的点到根路径的最大值,h[i]为对应的方案数。
__attribute__((optimize("-O2")))void add(int u,int v,int w) {
to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt; val[cnt]=w;
}
__attribute__((optimize("-O2")))void get_root(int x,int y) {
RR int i; siz[x]=1; f[x]=0;
for(i=head[x];i;i=nxt[i]) {
if(to[i]!=y&&!used[to[i]]) {
get_root(to[i],x);
siz[x]+=siz[to[i]];
f[x]=max(f[x],siz[to[i]]);
}
}
f[x]=max(f[x],sum-siz[x]);
if(f[x]<f[root]) root=x;
}
__attribute__((optimize("-O2")))void get_dep(int x,int y) {
maxdep=max(maxdep,dep[x]);
siz[x]=1;
RR int i;
for(i=head[x];i;i=nxt[i]) {
if(to[i]!=y&&!used[to[i]]) {
d[to[i]]=d[x]+val[i];
dep[to[i]]=dep[x]+1;
if(t1[dep[to[i]]]<d[to[i]]) {
t1[dep[to[i]]]=d[to[i]]; t2[dep[to[i]]]=1;
}else if(t1[dep[to[i]]]==d[to[i]]) {
t2[dep[to[i]]]++;
}
get_dep(to[i],x);
siz[x]+=siz[to[i]];
}
}
}
__attribute__((optimize("-O2")))void work(int x) {
maxmaxdep=0;
used[x]=1;
RR int i,j;
for(i=head[x];i;i=nxt[i]) {
if(!used[to[i]]) {
maxdep=1;
d[to[i]]=val[i];
dep[to[i]]=1; t1[1]=val[i]; t2[1]=1;
get_dep(to[i],x);
for(j=1;j<=maxdep&&j<=K;j++) {
if(ans<t1[j]+g[K-j]) ans=t1[j]+g[K-j],tot=t2[j]*h[K-j];
else if(ans==t1[j]+g[K-j]) tot+=t2[j]*h[K-j];
}
for(j=1;j<=maxdep&&j<=K;j++) {
if(t1[j]>g[j]) g[j]=t1[j],h[j]=t2[j];
else if(t1[j]==g[j]) h[j]+=t2[j];
}
for(j=1;j<=maxdep;j++) t1[j]=-1<<30,t2[j]=0;
maxmaxdep=max(maxmaxdep,maxdep);
}
}

for(i=1;i<=maxmaxdep&&i<=K;i++) g[i]=-1<<30,h[i]=0;
for(i=head[x];i;i=nxt[i]) {
if(!used[to[i]]) {
root=0;
sum=siz[to[i]];
get_root(to[i],x);
work(root);
}
}
}
__attribute__((optimize("-O2")))void solve() {
sum=n; root=0; f[0]=1<<30;
get_root(1,0); work(root);
printf("%d %d\n",ans,tot);
}
}F;
__attribute__((optimize("-O2")))void dfs(int x) {
RR int i;
dfn[x]=1;
sort(v[x].begin(),v[x].end(),cmp);
for(i=0;i<(int)v[x].size();i++) {
int t=v[x][i],c=val[t],v=to[t];
if(!dfn[v]) {
dfn[v]=1; F.add(x,v,c); F.add(v,x,c); dfs(v);
}
}
}
__attribute__((optimize("-O2")))int main() {
n=rd(); m=rd(); K=rd(); K--;
RR int i,x,y,z;
for(i=1;i<=m;i++) {
x=rd(); y=rd(); z=rd();
add(x,y,z); add(y,x,z);
}
dij();
dfs(1);
F.h[0]=1;
F.solve();
}

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: