[FJOI2014]最短路径树问题
代码能力练啊练
写了道没有任何思维的题
代码如下:
#include<bits/stdc++.h> #define N 200005 using namespace std; int n,m,K,x,y,z,kk,kkk,sum,rt,ans,min1,ans1,num[N],max1[N],q[N],dis[N],sz[N],head[N],head1[N];bool vis[N],done[N]; struct Edge{int nxt,to,step;}e[N*2],e1[N*2]; inline void link(int x,int y,int z){e[++kk].nxt=head[x];e[kk].to=y;e[kk].step=z;head[x]=kk;} inline void link1(int x,int y,int z){e1[++kkk].nxt=head1[x];e1[kkk].to=y;e1[kkk].step=z;head1[x]=kkk;} inline void spfa(){ int left1=1,right1=1;q[left1]=1; memset(dis,63,sizeof(dis));dis[1]=0; while (left1<=right1){ int u=q[left1++]; for (int i=head1[u];i;i=e1[i].nxt){ int v=e1[i].to; if (dis[v]>dis[u]+e1[i].step){ dis[v]=dis[u]+e1[i].step; q[++right1]=v; } } } //for (int i=1;i<=n;i++) printf("%d ",dis[i]);puts(""); } priority_queue<int>Q; inline void buildtree(){ memset(vis,0,sizeof(vis)); Q.push(-1);vis[1]=1; while (!Q.empty()){ int u=-Q.top();Q.pop(); for (int i=head1[u];i;i=e1[i].nxt){ int v=e1[i].to; if (!vis[v]&&dis[v]==dis[u]+e1[i].step){ link(u,v,e1[i].step);link(v,u,e1[i].step); //cerr<<"link: "<<u<<"->"<<v<<" step: "<<e1[i].step<<endl; Q.push(-v);vis[v]=1; } } } } void findroot(int u,int fa){ sz[u]=1;int mx=0; for (int i=head[u];i;i=e[i].nxt){ int v=e[i].to; if (v==fa||done[v]) continue; findroot(v,u); sz[u]+=sz[v]; mx=max(mx,sz[v]); } mx=max(mx,sum-sz[u]); if (mx<min1) min1=mx,rt=u; } void get1(int u,int fa,int dep,int summ){ ans1=max(ans1,max1[K-dep]+summ); if (dep==K) return; for (int i=head[u];i;i=e[i].nxt){ int v=e[i].to; if (v==fa||done[v]) continue; get1(v,u,dep+1,summ+e[i].step); } } void cover(int u,int fa,int dep,int summ){ max1[dep]=max(max1[dep],summ); if (dep==K) return; for (int i=head[u];i;i=e[i].nxt){ int v=e[i].to; if (v==fa||done[v]) continue; cover(v,u,dep+1,summ+e[i].step); } } void solve1(int u){ //cerr<<u<<endl; done[u]=1; memset(max1,0,sizeof(max1)); for (int i=head[u];i;i=e[i].nxt){ int v=e[i].to; if (done[v]) continue; get1(v,u,1,e[i].step); cover(v,u,1,e[i].step); } for (int i=head[u];i;i=e[i].nxt){ int v=e[i].to; if (done[v]) continue; sum=sz[v];min1=1e9; findroot(v,u); solve1(rt); } } void dfs1(int u,int fa,int dep,int summ){ if (max1[K-dep]+summ==ans1) ans+=num[K-dep]; for (int i=head[u];i;i=e[i].nxt){ int v=e[i].to; if (v==fa||done[v]) continue; dfs1(v,u,dep+1,summ+e[i].step); } } void dfs2(int u,int fa,int dep,int summ){ if (max1[dep]==summ) num[dep]++; else if (max1[dep]<summ) max1[dep]=summ,num[dep]=1; for (int i=head[u];i;i=e[i].nxt){ int v=e[i].to; if (v==fa||done[v]) continue; dfs2(v,u,dep+1,summ+e[i].step); } } void solve(int u){ //cerr<<u<<endl; done[u]=1; memset(max1,0,sizeof(max1)); memset(num,0,sizeof(num));num[0]=1;//num[i]经过i条边且最大的边数,注意自己构成一条的情况 for (int i=head[u];i;i=e[i].nxt){ int v=e[i].to; if (done[v]) continue; dfs1(v,u,1,e[i].step); dfs2(v,u,1,e[i].step); } for (int i=head[u];i;i=e[i].nxt){ int v=e[i].to; if (done[v]) continue; sum=sz[v];min1=1e9; findroot(v,u); solve(rt); } } int main(){ scanf("%d%d%d",&n,&m,&K);K--; for (int i=1;i<=m;i++){ scanf("%d%d%d",&x,&y,&z); link1(x,y,z);link1(y,x,z); } spfa();buildtree(); sum=n;min1=1e9; findroot(1,-1); solve1(rt); printf("%d ",ans1); memset(done,0,sizeof(done)); sum=n;min1=1e9; findroot(1,-1); solve(rt); printf("%d\n",ans); return 0; }