luogu 2993 [FJOI2014]最短路径树问题 Dijkstra+点分治
挺简单的,但是给人一种把两个问题强行弄到一起的感觉.
十分不好写.
Code:
#include <queue> #include <cstdio> #include <vector> #include <algorithm> #define N 100007 #define ll long long #define inf 1000000004 #define setIO(s) freopen(s".in","r",stdin) using namespace std; int K,n,m; namespace tree { ll answer; int edges,root,sn,maxdep,tl,best; int hd[N],to[N],nex[N],val[N]; int size[N],mx[N],vis[N],f[N],g[N],bu[N],cntf[N],cntg[N]; void addedge(int u,int v,int c) { nex[++edges]=hd[u],hd[u]=edges,to[edges]=v,val[edges]=c; } void getroot(int u,int ff) { size[u]=1,mx[u]=0; for(int i=hd[u];i;i=nex[i]) { int v=to[i]; if(!vis[v]&&v!=ff) getroot(v,u), size[u]+=size[v], mx[u]=max(mx[u], size[v]); } mx[u]=max(mx[u],sn-size[u]); if(mx[u]<mx[root]) root=u; } void dfs(int u,int ff,int depth,int p) { if(depth>=g[p]) { if(depth==g[p]) ++cntg[p]; else { if(!g[p]) bu[++tl]=p; g[p]=depth, cntg[p]=1; } } for(int i=hd[u];i;i=nex[i]) { int v=to[i]; if(v==ff||vis[v]) continue; dfs(v,u,depth+val[i],p+1); } } void calc(int u) { int i,j,cur=0; cntf[0]=1,tl=0; for(i=hd[u];i;i=nex[i]) { int v=to[i]; if(vis[v]) continue; dfs(v,u,val[i],1); for(j=cur+1;j<=tl;++j) { if(K-1<bu[j]) continue; if(g[bu[j]]+f[K-bu[j]-1]==best) { answer+=(ll)(cntg[bu[j]]*cntf[K-bu[j]-1]); } else if(g[bu[j]]+f[K-bu[j]-1]>best) { best=g[bu[j]]+f[K-bu[j]-1]; answer=(ll)(cntg[bu[j]]*cntf[K-bu[j]-1]); } } for(j=cur+1;j<=tl;++j) { if(g[bu[j]]==f[bu[j]]) cntf[bu[j]]+=cntg[bu[j]]; else if(g[bu[j]]>f[bu[j]]) { cntf[bu[j]]=cntg[bu[j]]; f[bu[j]]=g[bu[j]]; } } for(j=cur+1;j<=tl;++j) cntg[bu[j]]=g[bu[j]]=0; cur=tl; } for(i=1;i<=cur;++i) cntf[bu[i]]=cntg[bu[i]]=f[bu[i]]=g[bu[i]]=0; } void solve(int u) { vis[u]=1; calc(u); for(int i=hd[u];i;i=nex[i]) if(!vis[to[i]]) sn=size[to[i]],root=0,getroot(to[i],u),solve(root); } int main() { root=0,mx[0]=inf,sn=n; getroot(1,0),solve(root); printf("%d %lld\n",best,answer); return 0; } }; namespace Dijkstra { int d[N],done[N],vis[N]; struct Edge { int to,val; Edge(int to=0,int val=0):to(to),val(val){} }; bool cmp(Edge a,Edge b) { return a.to<b.to; } struct Node { int u,dis; Node(int u=0,int dis=0):u(u),dis(dis){} bool operator<(Node a)const { return a.dis<dis; } }; priority_queue<Node>q; vector<Edge>G[N]; void add(int u,int v,int c) { G[u].push_back(Edge(v,c)); } void dfs(int u) { vis[u]=1; for(int i=0;i<G[u].size();++i) if(!vis[G[u][i].to]&&d[u]+G[u][i].val==d[G[u][i].to]) { vis[G[u][i].to]=1; tree::addedge(u,G[u][i].to,G[u][i].val); tree::addedge(G[u][i].to,u,G[u][i].val); dfs(G[u][i].to); } } void build_tree() { int i; for(i=0;i<=n;++i) d[i]=inf; q.push(Node(1,0)), d[1]=0; while(!q.empty()) { Node e=q.top();q.pop(); int u=e.u; if(done[u]) continue; done[u]=1; for(i=0;i<G[u].size();++i) { Edge h=G[u][i]; if(d[h.to]>d[u]+h.val) { d[h.to]=d[u]+h.val; q.push(Node(h.to,d[h.to])); } } } for(i=1;i<=n;++i) sort(G[i].begin(),G[i].end(),cmp); dfs(1); } }; int main() { int i,j; // setIO("input"); scanf("%d%d%d",&n,&m,&K); for(i=1;i<=m;++i) { int a,b,c; scanf("%d%d%d",&a,&b,&c); Dijkstra::add(a,b,c); Dijkstra::add(b,a,c); } Dijkstra::build_tree(); tree::main(); return 0; }