[BZOJ4016][FJOI2014]最短路徑樹問題
阿新 • • 發佈:2018-06-30
end += pro div AI 強行 IT modify tdi
bzoj
luogu
loj
description
給你一張\(n\)點\(m\)條邊的無向圖,從\(1\)號點出發沿著最短路走到每一個節點,若最短路有多條則走節點編號字典序最小的那條。可以證明走過的邊是一棵樹。求這棵樹上所有包含\(k\)個節點的簡單路徑的最長長度以及這樣的路徑條數。
\(n\le30000,m\le60000,2\le k \le n\)
sol
強行二合一而已。
先對原圖跑一邊\(Dijkstra\)求出到每個點的最短路,然後\(dfs\)一遍就可以把最短路樹給建出來。
對於路徑統計的問題,考慮點分治,每次統計所有過重心的路徑,開一個桶表示到重心經過的邊數為\(i\)的最大長度以及方案數。每次要先更新答案再加入桶避免重復計算。
code
由於bzoj評測機的某種玄學操作,只要在結構體裏面調用遞歸函數就會出錯。
所以以下這份代碼無法在bzoj上AC。
不過在luogu和loj上都可以AC呀。
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
int gi(){
int x=0,w=1;char ch=getchar();
while ((ch<'0'||ch>'9' )&&ch!='-') ch=getchar();
if (ch=='-') w=0,ch=getchar();
while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return w?x:-x;
}
#define pi pair<int,int>
#define mk make_pair
const int N = 150000;
int n,m,k;pi ans;
void upt(pi &a,pi b){
if (a.first<b.first) a=b;
else if (a.first==b.first) a.second+=b.second;
}
struct Tree{
int to[N],nxt[N],ww[N],head[N],cnt,sz[N],w[N],vis[N],sum,root;pi f[N];
void link(int u,int v,int w){
to[++cnt]=v;nxt[cnt]=head[u];ww[cnt]=w;head[u]=cnt;
}
void getroot(int u,int fa){
sz[u]=1;w[u]=0;
for (int e=head[u];e;e=nxt[e])
if (to[e]!=fa&&!vis[to[e]]){
getroot(to[e],u);
sz[u]+=sz[to[e]];
w[u]=max(w[u],sz[to[e]]);
}
w[u]=max(w[u],sum-sz[u]);
if (w[u]<w[root]) root=u;
}
void query(int u,int fa,int dep,int dis){
upt(ans,mk(dis+f[k-dep].first,f[k-dep].second));
if (k==dep) return;
for (int e=head[u];e;e=nxt[e])
if (to[e]!=fa&&!vis[to[e]])
query(to[e],u,dep+1,dis+ww[e]);
}
void modify(int u,int fa,int dep,int dis){
upt(f[dep],mk(dis,1));if (k==dep) return;
for (int e=head[u];e;e=nxt[e])
if (to[e]!=fa&&!vis[to[e]])
modify(to[e],u,dep+1,dis+ww[e]);
}
void clear(int u,int fa,int dep,int dis){
f[dep]=mk(0,0);if (k==dep) return;
for (int e=head[u];e;e=nxt[e])
if (to[e]!=fa&&!vis[to[e]])
clear(to[e],u,dep+1,dis+ww[e]);
}
void solve(int u){
vis[u]=1;upt(f[0],mk(0,1));
for (int e=head[u];e;e=nxt[e])
if (!vis[to[e]]) query(to[e],0,1,ww[e]),modify(to[e],0,1,ww[e]);
for (int e=head[u];e;e=nxt[e])
if (!vis[to[e]]) clear(to[e],0,1,ww[e]);
for (int e=head[u];e;e=nxt[e])
if (!vis[to[e]]) root=0,sum=sz[to[e]],getroot(to[e],0),solve(root);
}
void work(){
w[0]=sum=n;getroot(1,0);solve(root);
printf("%d %d\n",ans.first,ans.second);
}
}T;
struct Graph{
int to[N],nxt[N],ww[N],head[N],cnt,dis[N],vis[N],dfn[N],tim;
vector<int>v[N];
priority_queue<pi,vector<pi>,greater<pi> >Q;
void link(int u,int v,int w){
to[++cnt]=v;nxt[cnt]=head[u];ww[cnt]=w;head[u]=cnt;
}
void dfs(int u){
dfn[u]=++tim;
for (int e=head[u];e;e=nxt[e])
if (dis[to[e]]==dis[u]+ww[e])
v[u].push_back(to[e]);
sort(v[u].begin(),v[u].end());
for (int i=0,sz=v[u].size();i<sz;++i)
if (!dfn[v[u][i]]){
T.link(u,v[u][i],dis[v[u][i]]-dis[u]);
T.link(v[u][i],u,dis[v[u][i]]-dis[u]);
dfs(v[u][i]);
}
}
void work(){
memset(dis,63,sizeof(dis));
dis[1]=0;Q.push(mk(0,1));
while (!Q.empty()){
int u=Q.top().second;Q.pop();
if (vis[u]) continue;vis[u]=1;
for (int e=head[u];e;e=nxt[e])
if (dis[to[e]]>dis[u]+ww[e])
dis[to[e]]=dis[u]+ww[e],Q.push(mk(dis[to[e]],to[e]));
}
dfs(1);
}
}G;
int main(){
n=gi();m=gi();k=gi()-1;
for (int i=1;i<=m;++i){
int u=gi(),v=gi(),w=gi();
G.link(u,v,w);G.link(v,u,w);
}
G.work();T.work();return 0;
}
[BZOJ4016][FJOI2014]最短路徑樹問題