zoukankan      html  css  js  c++  java
  • 【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
    ",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
    ",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
    ",av,ac);
    }
  • 相关阅读:
    octotree神器 For Github and GitLab 火狐插件
    实用篇如何使用github(本地、远程)满足基本需求
    PPA(Personal Package Archives)简介、兴起、使用
    Sourse Insight使用过程中的常使用功能简介
    Sourse Insight使用教程及常见的问题解决办法
    github 遇到Permanently added the RSA host key for IP address '192.30.252.128' to the list of known hosts问题解决
    二叉查找树的C语言实现(一)
    初识内核链表
    container_of 和 offsetof 宏详解
    用双向链表实现一个栈
  • 原文地址:https://www.cnblogs.com/shxnb666/p/11278517.html
Copyright © 2011-2022 走看看