【BZOJ4016】【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个点的路径最长为多长,第二个整数表示这样的不同的最长路径有多少条。
n<=30000,m<=60000,2<=K<=n
题解:
一眼题啊。。。SBFA写挂能怪谁QAQ
先把最小路径树建出来,然后就是点分治经典问题了;
关于最小路径树:
先以1为源点跑一边最短路,然后把对最短路没有贡献的边去掉,再按照字典序dfs一次把非树边去掉(有可能有多个最短路)即可。
代码:
1 #include<algorithm>
2 #include<iostream>
3 #include<cstring>
4 #include<cstdio>
5 #include<cmath>
6 #include<queue>
7 #define inf 2147483647
8 #define eps 1e-9
9 using namespace std;
10 typedef long long ll;
11 struct edge{
12 int v,w,next;
13 }a[200001],_a[200001],__a[200001];
14 struct _edge{
15 int u,v,w;
16 friend bool operator <(_edge a,_edge b){
17 return a.u==b.u?a.v>b.v:a.u<b.u;
18 }
19 }e[200001];
20 int n,m,k,u,v,w,ans=0,anss,rt,S,tot=0,_tot=0,__tot=0,siz[200001],mx[200001],head[200001],_head[200001],__head[200001],f[200001],g[200001],_f[200001],_g[200001],dis[200001];
21 bool used[200001],vis[200001];
22 void add(int u,int v,int w){
23 a[++tot].v=v;
24 a[tot].w=w;
25 a[tot].next=head[u];
26 head[u]=tot;
27 }
28 void _add(int u,int v,int w){
29 _a[++_tot].v=v;
30 _a[_tot].w=w;
31 _a[_tot].next=_head[u];
32 _head[u]=_tot;
33 }
34 void __add(int u,int v,int w){
35 __a[++__tot].v=v;
36 __a[__tot].w=w;
37 __a[__tot].next=__head[u];
38 __head[u]=__tot;
39 }
40 void spfa(){
41 queue<int>q;
42 bool isin[200001];
43 memset(isin,0,sizeof(isin));
44 q.push(1);
45 isin[1]=true;
46 dis[1]=0;
47 while(!q.empty()){
48 int u=q.front();
49 q.pop();
50 isin[u]=false;
51 for(int tmp=_head[u];tmp!=-1;tmp=_a[tmp].next){
52 int v=_a[tmp].v;
53 if(dis[v]>dis[u]+_a[tmp].w){
54 dis[v]=dis[u]+_a[tmp].w;
55 if(!isin[v]){
56 isin[v]=true;
57 q.push(v);
58 }
59 }
60 }
61 }
62 sort(e+1,e+m*2+1);
63 for(int i=1;i<=m*2;i++){
64 if(dis[e[i].v]==dis[e[i].u]+e[i].w){
65 __add(e[i].u,e[i].v,e[i].w);
66 }
67 }
68 }
69 void build(int u){
70 used[u]=true;
71 for(int tmp=__head[u];tmp!=-1;tmp=__a[tmp].next){
72 int v=__a[tmp].v,w=__a[tmp].w;
73 if(!used[v]){
74 //printf("%d %d %d\n",u,v,w);
75 add(u,v,w);
76 add(v,u,w);
77 build(v);
78 }
79 }
80 }
81 void dfsrt(int u,int fa){
82 siz[u]=1;
83 mx[u]=0;
84 for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
85 int v=a[tmp].v;
86 if(v!=fa&&!vis[v]){
87 dfsrt(v,u);
88 mx[u]=max(mx[u],siz[v]);
89 siz[u]+=siz[v];
90 }
91 }
92 mx[u]=max(mx[u],S-siz[u]);
93 if(mx[u]<mx[rt])rt=u;
94 }
95 void dfs(int u,int fa,int dpt,int ww){
96 if(dpt>k)return;
97 if(ww>_f[dpt]){
98 _f[dpt]=ww;
99 _g[dpt]=1;
100 }else if(ww==_f[dpt]){
101 _g[dpt]++;
102 }
103 for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
104 int v=a[tmp].v;
105 if(v!=fa&&!vis[v]){
106 dfs(v,u,dpt+1,ww+a[tmp].w);
107 }
108 }
109 }
110 void divide(int u){
111 f[0]=0,g[0]=1;
112 for(int i=1;i<=k;i++)f[i]=g[i]=0;
113 vis[u]=true;
114 for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
115 int v=a[tmp].v,w=a[tmp].w;
116 if(!vis[v]){
117 for(int i=0;i<=k;i++)_f[i]=_g[i]=0;
118 dfs(v,0,1,w);
119 for(int i=1;i<=k;i++){
120 if(ans<f[k-i]+_f[i]){
121 ans=f[k-i]+_f[i];
122 anss=g[k-i]*_g[i];
123 }else if(ans==f[k-i]+_f[i]){
124 anss+=g[k-i]*_g[i];
125 }
126 }
127 for(int i=1;i<=k;i++){
128 if(f[i]<_f[i]){
129 f[i]=_f[i];
130 g[i]=_g[i];
131 }else if(f[i]==_f[i]){
132 g[i]+=_g[i];
133 }
134 }
135 }
136 }
137 for(int tmp=head[u];tmp!=-1;tmp=a[tmp].next){
138 int v=a[tmp].v;
139 if(!vis[v]){
140 rt=0,S=siz[v];
141 dfsrt(v,0);
142 divide(rt);
143 }
144 }
145 }
146 int main(){
147 memset(dis,0x3f,sizeof(dis));
148 memset(head,-1,sizeof(head));
149 memset(_head,-1,sizeof(_head));
150 memset(__head,-1,sizeof(__head));
151 memset(used,0,sizeof(used));
152 memset(vis,0,sizeof(vis));
153 scanf("%d%d%d",&n,&m,&k);
154 k--;
155 for(int i=1;i<=m;i++){
156 scanf("%d%d%d",&u,&v,&w);
157 _add(u,v,w);
158 _add(v,u,w);
159 e[i*2-1]=(_edge){u,v,w};
160 e[i*2]=(_edge){v,u,w};
161 }
162 spfa();
163 build(1);
164 mx[rt=0]=666666,S=n;
165 dfsrt(1,0);
166 divide(rt);
167 printf("%d %d",ans,anss);
168 return 0;
169 }
PS:BZOJ数据极水,我写了SPFA+没判字典序都过了