BZOJ4016: [FJOI2014]最短路径树问题
题目:http://www.lydsy.com/JudgeOnline/problem.php?id=4016
最短路+点分治。。
首先要把最短路径树做出来吧。。于是先跑一遍spfa,然后bfs一遍就可以建出树了。。
然后点分。。对于以重心为根的那棵子树,一棵一棵子树拿出来,维护处dep和dis(到根的距离),然后更新答案。
设g[i][0]为深度为i的路径的最大距离,g[i][1]为当前这个最大距离下的路径个数。
这样维护还算是比较简单的吧。。。
感人肺腑的是没怎么调,过样例就A了。。更感人肺腑的是速度垫底了TAT。。
#include<cstring> #include<iostream> #include<cstdio> #include<algorithm> #include<queue> #define rep(i,l,r) for (int i=l;i<=r;i++) #define down(i,l,r) for (int i=l;i>=r;i--) #define clr(x,y) memset(x,y,sizeof(x)) #define maxn 60059 #define inf int(1e9) using namespace std; int read(){ int x=0,f=1; char ch=getchar(); while (!isdigit(ch)){if (ch=='-') f=-1; ch=getchar();} while (isdigit(ch)){x=x*10+ch-'0'; ch=getchar();} return x*f; } struct data{int obj,pre,c; }e[maxn*4],ed[maxn*4]; int head[maxn],head2[maxn],s[maxn],dis[maxn],vis[maxn],q[maxn],fa[maxn],dep[maxn],g[maxn][2],sz[maxn]; int n,m,sum,K,ans,ans2,mx,rt,tot,tot2; void insert(int x,int y,int z){ e[++tot].obj=y; e[tot].pre=head[x]; head[x]=tot; e[tot].c=z; } void insert2(int x,int y,int z){ ed[++tot2].obj=y; ed[tot2].pre=head2[x]; head2[x]=tot2; ed[tot2].c=z; } void spfa(){ queue<int> q; q.push(1); clr(vis,0); vis[1]=1; rep(i,1,n) dis[i]=inf; dis[1]=0; while (!q.empty()){ int u=q.front(); q.pop(); vis[u]=0; for (int j=head2[u];j;j=ed[j].pre){ int v=ed[j].obj; if (dis[v]>dis[u]+ed[j].c){ dis[v]=dis[u]+ed[j].c; if (!vis[v]) vis[v]=1,q.push(v); } } vis[u]=0; } } void bfs(){ priority_queue<int> q; q.push(-1); clr(vis,0); vis[1]=1; while (!q.empty()){ int u=-q.top(); q.pop(); for (int j=head2[u];j;j=ed[j].pre){ int v=ed[j].obj; if (vis[v]||dis[v]!=dis[u]+ed[j].c) continue; insert(u,v,ed[j].c); insert(v,u,ed[j].c); vis[v]=1; q.push(-v); } } } int dfs(int u,int f){ s[u]=1; for (int j=head[u];j;j=e[j].pre){ int v=e[j].obj; if (v!=f) s[u]+=dfs(v,u); } return s[u]; } void getroot(int u,int f){ sz[u]=0; for (int j=head[u];j;j=e[j].pre){ int v=e[j].obj; if (vis[v]||v==f) continue; getroot(v,u); sz[u]=max(sz[u],s[v]); } sz[u]=max(sz[u],sum-s[u]); if (sz[u]<mx) mx=sz[u],rt=u; } void go(int u){ for (int j=head[u];j;j=e[j].pre){ int v=e[j].obj; if (vis[v]) continue; dep[v]=1; dis[v]=e[j].c; fa[v]=u; int l=0,r=1; q[1]=v; while (l<r){ int now=q[++l]; for (int k=head[now];k;k=e[k].pre){ int v=e[k].obj; if (v==fa[now]||vis[v]) continue; fa[v]=now; dis[v]=dis[now]+e[k].c; dep[v]=dep[now]+1; q[++r]=v; } } rep(i,1,r){ int x=dep[q[i]]; fa[q[i]]=0; if (x>=K) break; if (dis[q[i]]+g[K-x-1][0]>ans) ans=dis[q[i]]+g[K-x-1][0],ans2=g[K-x-1][1]; else if (dis[q[i]]+g[K-x-1][0]==ans) ans2+=g[K-x-1][1]; } rep(i,1,r){ int x=dep[q[i]]; if (x>=K) break; if (x==K-1){ if (dis[q[i]]>ans) ans=dis[q[i]],ans2=1; else if (dis[q[i]]==ans) ans2++; continue; } if (dis[q[i]]>g[x][0]) g[x][0]=dis[q[i]],g[x][1]=1; else if (dis[q[i]]==g[x][0]) g[x][1]++; } } } void solve(int u){ rt=0; mx=inf; getroot(u,0); rep(i,1,K) g[i][0]=-inf,g[i][1]=0; go(rt); vis[rt]=1; for (int j=head[rt];j;j=e[j].pre){ int v=e[j].obj; if (!vis[v]) sum=s[v],solve(v); } } int main(){ n=read(); m=read(); K=read(); rep(i,1,m) { int x=read(),y=read(),z=read(); insert2(x,y,z); insert2(y,x,z); } spfa(); bfs(); dfs(1,0); clr(vis,0); sum=n; solve(1); printf("%d %d\n",ans,ans2); return 0; }