description
給你一張$n$點$m$條邊的無向圖,從$1$號點出發沿着最短路走到每個節點,若最短路有多條則走節點編號字典序最小的那條。能夠證實走過的邊是一棵樹。求這棵樹上全部包含$k$個節點的簡單路徑的最長長度以及這樣的路徑條數。 $n\le30000,m\le60000,2\le k \le n$函數
sol
強行二合一而已。 先對原圖跑一邊$Dijkstra$求出到每一個點的最短路,而後$dfs$一遍就能夠把最短路樹給建出來。 對於路徑統計的問題,考慮點分治,每次統計全部太重心的路徑,開一個桶表示到重心通過的邊數爲$i$的最大長度以及方案數。每次要先更新答案再加入桶避免重複計算。spa
code
因爲bzoj評測機的某種玄學操做,只要在結構體裏面調用遞歸函數就會出錯。 因此如下這份代碼沒法在bzoj上AC。 不過在luogu和loj上均可以AC呀。code
#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; }