BZOJ 4016 [FJOI2014]最短路径树问题
Posted Troy Ricardo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ 4016 [FJOI2014]最短路径树问题相关的知识,希望对你有一定的参考价值。
题目链接:
题解:
我就是个智障。明明是道大水题,硬是拖了6h。
关于这道题我唯一想说的就是,记得更新拆分后的子树大小!!!我就是ZZ恒(QwQ。
代码:
1 #define Troy 10/26/2017 2 3 #include <bits/stdc++.h> 4 5 using namespace std; 6 7 inline int read(){ 8 int s=0,k=1;char ch=getchar(); 9 while(ch<‘0‘|ch>‘9‘) ch==‘-‘?k=-1:0,ch=getchar(); 10 while(ch>47&ch<=‘9‘) s=s*10+(ch^48),ch=getchar(); 11 return s*k; 12 } 13 14 const int N=3e5+5; 15 16 int n,m,K; 17 18 struct edges{ 19 int v,w;edges *last; 20 }edge[N<<1],*head[N];int cnt; 21 22 inline void push(int u,int v,int w){ 23 edge[++cnt]=(edges){v,w,head[u]};head[u]=edge+cnt; 24 } 25 26 int q[N],dis[N],from[N]; 27 bool vis[N]; 28 29 inline void dfs(int x){ 30 vis[x]=true; 31 vector<int > G; 32 for(edges *i=head[x];i;i=i->last) if(!vis[i->v]&&dis[i->v]==dis[x]+i->w) 33 G.push_back(i->v); 34 sort(G.begin(),G.end()); 35 for(int i=0;i<G.size();i++){ 36 if(vis[G[i]]) continue; 37 dfs(G[i]); 38 from[G[i]]=x; 39 } 40 } 41 42 inline void spfa(){ 43 int l=0,r=1; 44 q[0]=1; 45 memset(dis,127,sizeof(dis)); 46 dis[1]=0; 47 while(l!=r){ 48 int x=q[l++];if(l==N) l=0; 49 for(edges *i=head[x];i;i=i->last){ 50 if(dis[x]+i->w<dis[i->v]){ 51 dis[i->v]=dis[x]+i->w; 52 if(!vis[i->v]) 53 vis[i->v]=true,q[r++]=i->v; 54 if(r==N) r=0; 55 } 56 } 57 vis[x]=false; 58 } 59 dfs(1); 60 } 61 62 int heavy[N],root,size[N],tot,top,ans=0,sum,T[N],t[N],clocks,cnts[N]; 63 64 inline void dfs(int x,int fa){ 65 size[x]=1,heavy[x]=0; 66 for(edges *i=head[x];i;i=i->last)if(i->v!=fa&&(!vis[i->v])){ 67 dfs(i->v,x); 68 size[x]+=size[i->v]; 69 heavy[x]=max(heavy[x],size[i->v]); 70 } 71 heavy[x]=max(heavy[x],tot-size[x]); 72 if(heavy[x]<=top) 73 top=heavy[x],root=x; 74 } 75 76 struct node{ 77 int v,w; 78 inline friend bool operator <(node x,node y){ 79 return size[x.v]<size[y.v]; 80 } 81 }sons[N]; 82 83 inline void calc(int x,int fa,int w,int deep){ 84 if(T[K-deep]==clocks){ 85 if(ans<t[K-deep]+w) 86 ans=t[K-deep]+w,sum=0; 87 if(ans==t[K-deep]+w) 88 sum+=cnts[K-deep]; 89 } 90 if(deep+1<K) 91 for(edges *i=head[x];i;i=i->last) if(i->v!=fa&&vis[i->v]==0){ 92 calc(i->v,x,w+i->w,deep+1); 93 } 94 } 95 96 inline void update(int x,int fa,int w,int deep){ 97 if(T[deep]==clocks){ 98 if(t[deep]<w) 99 t[deep]=w,cnts[deep]=0; 100 if(t[deep]==w) 101 cnts[deep]++; 102 } 103 else T[deep]=clocks,t[deep]=w,cnts[deep]=1; 104 if(deep<K) 105 for(edges *i=head[x];i;i=i->last) if(i->v!=fa&&vis[i->v]==0){ 106 update(i->v,x,w+i->w,deep+1); 107 } 108 } 109 110 inline void solve(int x){ 111 clocks++; 112 top=0x7fffffff; 113 dfs(x,x); 114 vis[root]=true; 115 x=root; 116 int num(0); 117 T[1]=clocks; 118 for(edges *i=head[x];i;i=i->last)if(vis[i->v]^1){ 119 sons[++num]=(node){i->v,i->w}; 120 } 121 sort(sons+1,sons+1+num); 122 for(int i=1;i<=num;i++){ 123 calc(sons[i].v,x,sons[i].w,1); 124 if(i<num) 125 update(sons[i].v,x,sons[i].w,2); 126 } 127 128 for(edges *i=head[x];i;i=i->last) if(vis[i->v]^1) 129 if(size[i->v]>=K){ 130 tot=size[i->v],solve(i->v); 131 } 132 133 } 134 135 int main(){ 136 n=read(),m=read(),K=read(); 137 for(int i=1,u,v,w;i<=m;i++){ 138 u=read(),v=read(),w=read(); 139 push(u,v,w);push(v,u,w); 140 } 141 spfa(); 142 memset(vis,0,sizeof(vis)); 143 memset(head,0,sizeof(head)); 144 cnt=0; 145 for(int i=2;i<=n;i++) 146 push(from[i],i,dis[i]-dis[from[i]]), 147 push(i,from[i],dis[i]-dis[from[i]]); 148 tot=n; 149 cnts[1]=1; 150 solve(1); 151 printf("%d %d\n",ans,sum); 152 }
以上是关于BZOJ 4016 [FJOI2014]最短路径树问题的主要内容,如果未能解决你的问题,请参考以下文章
BZOJ 4016: [FJOI2014]最短路径树问题( 最短路 + 点分治 )