您的位置:首页 > 其它

【BZOJ 4016】 [FJOI2014]最短路径树问题

2017-10-28 17:08 387 查看

题目链接:

  TP

题解:

   我就是个智障。明明是道大水题,硬是拖了6h。

  关于这道题我唯一想说的就是,记得更新拆分后的子树大小!!!我就是ZZ恒(QwQ。

代码:

  

#define Troy 10/26/2017

#include <bits/stdc++.h>

using namespace std;

inline int read(){
int s=0,k=1;char ch=getchar();
while(ch<'0'|ch>'9')    ch=='-'?k=-1:0,ch=getchar();
while(ch>47&ch<='9')    s=s*10+(ch^48),ch=getchar();
return s*k;
}

const int N=3e5+5;

int n,m,K;

struct edges{
int v,w;edges *last;
}edge[N<<1],*head
;int cnt;

inline void push(int u,int v,int w){
edge[++cnt]=(edges){v,w,head[u]};head[u]=edge+cnt;
}

int q
,dis
,from
;
bool vis
;

inline void dfs(int x){
vis[x]=true;
vector<int > G;
for(edges *i=head[x];i;i=i->last)   if(!vis[i->v]&&dis[i->v]==dis[x]+i->w)
G.push_back(i->v);
sort(G.begin(),G.end());
for(int i=0;i<G.size();i++){
if(vis[G[i]])   continue;
dfs(G[i]);
from[G[i]]=x;
}
}

inline void spfa(){
int l=0,r=1;
q[0]=1;
memset(dis,127,sizeof(dis));
dis[1]=0;
while(l!=r){
int x=q[l++];if(l==N)   l=0;
for(edges *i=head[x];i;i=i->last){
if(dis[x]+i->w<dis[i->v]){
dis[i->v]=dis[x]+i->w;
if(!vis[i->v])
vis[i->v]=true,q[r++]=i->v;
if(r==N)    r=0;
}
}
vis[x]=false;
}
dfs(1);
}

int heavy
,root,size
,tot,top,ans=0,sum,T
,t
,clocks,cnts
;

inline void dfs(int x,int fa){
size[x]=1,heavy[x]=0;
for(edges *i=head[x];i;i=i->last)if(i->v!=fa&&(!vis[i->v])){
dfs(i->v,x);
size[x]+=size[i->v];
heavy[x]=max(heavy[x],size[i->v]);
}
heavy[x]=max(heavy[x],tot-size[x]);
if(heavy[x]<=top)
top=heavy[x],root=x;
}

struct node{
int v,w;
inline friend bool operator <(node x,node y){
return size[x.v]<size[y.v];
}
}sons
;

inline void calc(int x,int fa,int w,int deep){
if(T[K-deep]==clocks){
if(ans<t[K-deep]+w)
ans=t[K-deep]+w,sum=0;
if(ans==t[K-deep]+w)
sum+=cnts[K-deep];
}
if(deep+1<K)
for(edges *i=head[x];i;i=i->last)   if(i->v!=fa&&vis[i->v]==0){
calc(i->v,x,w+i->w,deep+1);
}
}

inline void update(int x,int fa,int w,int deep){
if(T[deep]==clocks){
if(t[deep]<w)
t[deep]=w,cnts[deep]=0;
if(t[deep]==w)
cnts[deep]++;
}
else    T[deep]=clocks,t[deep]=w,cnts[deep]=1;
if(deep<K)
for(edges *i=head[x];i;i=i->last)   if(i->v!=fa&&vis[i->v]==0){
update(i->v,x,w+i->w,deep+1);
}
}

inline void solve(int x){
clocks++;
top=0x7fffffff;
dfs(x,x);
vis[root]=true;
x=root;
int num(0);
T[1]=clocks;
for(edges *i=head[x];i;i=i->last)if(vis[i->v]^1){
sons[++num]=(node){i->v,i->w};
}
sort(sons+1,sons+1+num);
for(int i=1;i<=num;i++){
calc(sons[i].v,x,sons[i].w,1);
if(i<num)
update(sons[i].v,x,sons[i].w,2);
}

for(edges *i=head[x];i;i=i->last)    if(vis[i->v]^1)
if(size[i->v]>=K){
tot=size[i->v],solve(i->v);
}

}

int main(){
n=read(),m=read(),K=read();
for(int i=1,u,v,w;i<=m;i++){
u=read(),v=read(),w=read();
push(u,v,w);push(v,u,w);
}
spfa();
memset(vis,0,sizeof(vis));
memset(head,0,sizeof(head));
cnt=0;
for(int i=2;i<=n;i++)
push(from[i],i,dis[i]-dis[from[i]]),
push(i,from[i],dis[i]-dis[from[i]]);
tot=n;
cnts[1]=1;
solve(1);
printf("%d %d\n",ans,sum);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: