【FJOI2014】最短路径树问题

题面

https://www.luogu.org/problem/P2993

题解

// luogu-judger-enable-o2
#include<cstdio>
#include<iostream>
#include<cstring>
#include<queue>
#include<vector>
#define ri register int
#define N 30500
#define INF 10000000000007LL
#define LL long long
using namespace std;
int n,m,k,cc=0;
vector<int> to[N],t[N],len[N],l[N];
int siz[N],b[N],bb[N];
bool vis[N];
LL dis[N],av=0,ac=0,a[N],aa[N];

LL A(int x) {
  if (x>=0) return a[x]; else return -1000000007;
}

struct node{
  int v; LL d;
  bool operator < (const node &rhs) const {
    if (d==rhs.d) return v>rhs.v; else return d>rhs.d;
  }
};

void addedge(int x,int y,int z){
  t[x].push_back(y); l[x].push_back(z);
  //t[y].push_back(x); l[y].push_back(z);
}

void dij() {
  for (ri i=1;i<=n;i++) dis[i]=INF;
  dis[1]=0;
  priority_queue<node> q;
  q.push((node){1,0});
  while (!q.empty()) {
    int x=q.top().v; q.pop();
    if (vis[x]) continue;
    vis[x]=1;
    for (ri i=0,ls=to[x].size();i<ls;i++) {
      int v=to[x][i];
      if (dis[x]+len[x][i]<dis[v]) {
        dis[v]=dis[x]+len[x][i];
        q.push((node){v,dis[v]});
      }
    }
  }
}

void build() {
  memset(vis,0,sizeof(vis));
  vis[1]=1;
  priority_queue<node> q;
  while (!q.empty()) q.pop();
  q.push((node){1,0});
  while (!q.empty()) {
    int x=q.top().v; q.pop();
    for (ri i=0,ls=to[x].size();i<ls;i++) if (dis[to[x][i]]==dis[x]+len[x][i] && !vis[to[x][i]]) {
      //cout<<x<<" "<<to[x][i]<<endl;
      cc++;
      vis[to[x][i]]=1;
      addedge(x,to[x][i],len[x][i]);
      addedge(to[x][i],x,len[x][i]);
      q.push((node){to[x][i],dis[to[x][i]]});
    }
  }
}

void findroot(int x,int ff,int &rt,int &rts,int tot) {
  int curs=0;
  siz[x]=1;
  for (ri i=0,ls=t[x].size();i<ls;i++) if (t[x][i]!=ff && !vis[t[x][i]]) {
    findroot(t[x][i],x,rt,rts,tot);
    if (siz[t[x][i]]>curs) curs=siz[t[x][i]];
    siz[x]+=siz[t[x][i]];
  }
  if (tot-siz[x]>curs) curs=tot-siz[x];
  if (curs<rts) rts=curs,rt=x;
}

void tonji(int x,int ff,int d,LL w,int &maxd) {
  if (w>aa[d]) aa[d]=w,bb[d]=0;
  if (w==aa[d]) bb[d]++;
  if (d>maxd) maxd=d;
  for (ri i=0,ls=t[x].size();i<ls;i++) if (t[x][i]!=ff && !vis[t[x][i]]) tonji(t[x][i],x,d+1,w+l[x][i],maxd);
}

void cnt(int x,int ff,int &tot) {
  tot++;
  for (ri i=0,ls=t[x].size();i<ls;i++) if (t[x][i]!=ff && !vis[t[x][i]]) cnt(t[x][i],x,tot);
}

void solve(int x) {
  // a[x] d==x maxw value
  // b[x] d==x maxw times
  a[0]=0; b[0]=1;
  vis[x]=1;
  int md=0;
  for (ri i=0,ls=t[x].size();i<ls;i++) if (!vis[t[x][i]]) {
    int maxd=0;
    tonji(t[x][i],x,1,l[x][i],maxd);
    md=max(md,maxd);
    //printf("%d %d %d\n",i,t[x][i],maxd);
    for (ri j=1;j<=maxd;j++) if (aa[j]+A(k-j-1)>av) av=aa[j]+A(k-j-1),ac=0;
    for (ri j=1;j<=maxd;j++) if (aa[j]+A(k-j-1)==av) {
      ac+=bb[j]*1LL*b[k-j-1];
      //printf("x=%d s=%d aa[%d]=%lld a[%d]=%lld bb[%d]=%d b[%d]=%d\n",x,t[x][i],j,aa[j],k-j-1,a[k-j-1],j,bb[j],k-j-1,b[k-j-1]);
      //cout<<x<<" "<<aa[j]<<" "<<a[k-j-1]<<" "<<bb[j]<<" "<<b[k-j-1]<<endl;
    }
    for (ri j=1;j<=maxd;j++) {
      if (aa[j]>a[j]) a[j]=aa[j],b[j]=0;
      if (aa[j]==a[j]) b[j]+=bb[j];
    }
    for (ri j=1;j<=maxd;j++) aa[j]=0,bb[j]=0;
  }

  for (ri i=0;i<=md;i++) a[i]=0,b[i]=0;

  for (ri i=0,ls=t[x].size();i<ls;i++) if (!vis[t[x][i]]) {
    int tot=0;
    cnt(t[x][i],x,tot);
    int rt=-1,rts=tot;
    findroot(t[x][i],x,rt,rts,tot);
    solve(rt);
  }
}

void dianfen() {
  memset(vis,0,sizeof(vis));
  int rt=-1,rts=n;
  findroot(1,1,rt,rts,n);
  solve(rt);
}

int main(){
  int a,b,c;
  scanf("%d %d %d",&n,&m,&k);
  for (ri i=1;i<=m;i++) {
    scanf("%d %d %d",&a,&b,&c);
    to[a].push_back(b); len[a].push_back(c);
    to[b].push_back(a); len[b].push_back(c);
  }
  dij();
  build();
  dianfen();
  printf("%lld %lld\n",av,ac);
}

 

posted @ 2019-07-31 19:17  HellPix  阅读(143)  评论(0编辑  收藏  举报