[题解](最短路(树))luogu_P5201_short cut

一开始想着最短路时统计一下到每个点的牛数量,但是没写出来

建最短路树是个不错的想法,正常跑一次最短路,枚举每个点的前驱,如果d[y]==d[x]+w就是树上的一条边,优先连编号小的,

建好树以后做一次dfs,枚举一下每个点的贡献取个最大值即可

#include<bits/stdc++.h>
#define mp make_pair
#define ll long long
using namespace std;
const int maxn=10010;
const int maxm=50010;
int n,m,t;ll ans;
priority_queue<pair<ll,int> >q;
struct node{
    int v,w,nxt;
}e[maxm*2],e2[maxm*2];
ll d[maxn],c[maxn],w[maxn];
bool v[maxn];
int head[maxn],cnt;
void add(int u,int v,int w){e[++cnt].v=v;e[cnt].w=w;e[cnt].nxt=head[u];head[u]=cnt;}
int head2[maxn],cnt2;
void add2(int u,int v,int w){e2[++cnt2].v=v;e2[cnt2].w=w;e2[cnt2].nxt=head2[u];head2[u]=cnt2;}
ll max(ll a,ll b){return a<b?b:a;}
void dij(){
    memset(d,0x3f,sizeof(d));
    d[1]=0;q.push(mp(0,1));
    while(!q.empty()){
        int x=q.top().second;q.pop();
        if(v[x])continue;v[x]=1;
        for(int i=head[x];i;i=e[i].nxt){
            int y=e[i].v,z=e[i].w;
            if(d[y]>d[x]+z){
                d[y]=d[x]+z;
                q.push(mp(-d[y],y));
            }
        }
    }
}
void dfs(int x){
    v[x]=1;
    for(int i=head2[x];i;i=e2[i].nxt){
        int y=e2[i].v;
        if(v[y])continue;
        dfs(y);w[x]+=w[y];
    }
    ans=max(ans,(ll)w[x]*(d[x]-t));
}
int main(){
    scanf("%d%d%d",&n,&m,&t);
    for(int i=1;i<=n;i++)scanf("%lld",&w[i]);
    for(int i=1,u,v,w;i<=m;i++){
        scanf("%d%d%d",&u,&v,&w);
        add(u,v,w);add(v,u,w);
    }
    dij();
    //建最短路树 
    memset(v,0,sizeof(v));
    for(int i=1;i<=n;i++){
        for(int j=head[i];j;j=e[j].nxt){
            int y=e[j].v,z=e[j].w;
            if(d[y]==d[i]+z && !v[y])
            v[y]=1,add2(i,y,z),add2(y,i,z);
        }
    }
    memset(v,0,sizeof(v));
    dfs(1);
    printf("%lld",ans);
}

猜你喜欢

转载自www.cnblogs.com/superminivan/p/10770743.html
cut