BZOJ016 [FJOI2014]最短路径树问题
【题意】
在最短路径树上,最长的包含K个点的简单路径长度为多长?长度为该最长长度的不同路径有多少条
【分析】
首先通过dij跑出最短路径,然后dfs一遍求出求最短路径树,注意到了每个点后,要把儿子节点按照标号排序
之后就是普通的点分治,开一个桶表示到重心经过的边数为i的最大长度以及方案数。每次要先更新答案再加入桶避免重复计算。
【代码】
#include<bits/stdc++.h> using namespace std; const int maxn=3e4+5; const int inf=0x3f3f3f3f; typedef pair<int,int> PII; #define mp make_pair #define pb push_back #define fi first #define se second vector <PII> G[maxn]; int n,m,k; int dis[maxn],vis[maxn]; void dijkstra() { for(int i=1;i<=n;i++) dis[i]=inf; dis[1]=0; priority_queue <PII> q; q.push(mp(-dis[1],1)); while(!q.empty()) { int u=q.top().se,v=q.top().fi; q.pop(); if(-v!=dis[u]) continue; for(int k=0;k<G[u].size();k++) { int to=G[u][k].fi; if(dis[to]>dis[u]+G[u][k].se) { dis[to]=dis[u]+G[u][k].se; q.push(mp(-dis[to],to)); } } } } int head[maxn],tot; struct edge { int to,nxt,v; }e[maxn<<1]; void add(int x,int y,int z) { e[++tot].to=y; e[tot].nxt=head[x]; e[tot].v=z; head[x]=tot; } void dfs(int u) { sort(G[u].begin(),G[u].end()); for(int k=0;k<G[u].size();k++) { int to=G[u][k].fi,v=G[u][k].se; if(dis[to]!=dis[u]+v || vis[to]) continue; vis[to]=1; add(to,u,v); add(u,to,v); dfs(to); } } int root,siz[maxn],size,gsiz,dep[maxn]; void findrt(int u,int fa) { siz[u]=1; int maxsiz=0; for(int i=head[u];i;i=e[i].nxt) { int to=e[i].to; if(to==fa || vis[to]) continue; findrt(to,u); siz[u]+=siz[to]; maxsiz=max(maxsiz,siz[to]); } maxsiz=max(maxsiz,size-siz[u]); if(maxsiz<gsiz) { gsiz=maxsiz; root=u; } } int ansdis,anscnt,cnt,num[maxn],len[maxn],t[maxn],t2[maxn]; void getdis(int u,int fa) { if(dep[u]>k) return; t[++cnt]=dis[u]; t2[cnt]=dep[u]; for(int i=head[u];i;i=e[i].nxt) { int to=e[i].to; if(to==fa || vis[to]) continue; dis[to]=dis[u]+e[i].v; dep[to]=dep[u]+1; getdis(to,u); } } int solve(int u) { int pre=cnt=0,res=0; // memset(num,0,sizeof(num)); // memset(len,0,sizeof(len)); num[0]=1; for(int i=head[u];i;i=e[i].nxt) { int to=e[i].to; if(vis[to]) continue; dis[to]=dis[u]+e[i].v; dep[to]=dep[u]+1; pre=cnt; getdis(to,u); for(int j=pre+1;j<=cnt;j++) { if(ansdis<t[j]+len[k-t2[j]-1]) { ansdis=t[j]+len[k-t2[j]-1]; res=num[k-t2[j]-1]; } else if(ansdis==t[j]+len[k-t2[j]-1]) res+=num[k-t2[j]-1]; } for(int j=pre+1;j<=cnt;j++) { if(len[t2[j]]==t[j]) ++num[t2[j]]; if(len[t2[j]]<t[j]) num[t2[j]]=1,len[t2[j]]=t[j]; } } for(int i=1;i<=cnt;i++) num[t2[i]]=0,len[t2[i]]=0; return res; } void divide(int u) { vis[u]=1; dis[u]=dep[u]=0; int pre=ansdis,tmp=solve(u); if(pre!=ansdis) anscnt=tmp; else anscnt+=tmp; for(int i=head[u];i;i=e[i].nxt) { int to=e[i].to; if(vis[to]) continue; size=siz[to]; root=0; gsiz=inf; findrt(to,0); divide(root); } } int main() { //freopen("a.in","r",stdin); //freopen("a.out","w",stdout); scanf("%d%d%d",&n,&m,&k); int x,y,z; for(int i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&z); G[x].pb(mp(y,z)); G[y].pb(mp(x,z)); } dijkstra(); memset(vis,0,sizeof(vis)); vis[1]=1; dfs(1); memset(vis,0,sizeof(vis)); size=n; gsiz=inf; findrt(1,0); divide(root); printf("%d %d\n",ansdis,anscnt); return 0; }

浙公网安备 33010602011771号