[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;
}

 

posted @ 2018-08-11 19:23  longint  阅读(84)  评论(0编辑  收藏  举报