zoukankan      html  css  js  c++  java
  • P2993 [FJOI2014]最短路径树问题

    思路:最短路+点分治

    提交:2次

    错因:更新桶的时候没有重置,而直接加上了。

    题解:

    对于构建最短路树,我们可以先跑最短路,然后dfs一遍连边。
    然后就是点分治了,还是一些桶,存点数为(x)的最长路径的条数。记得更新路径长度时桶要清零。

    代码

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<queue>
    #include<algorithm>
    #define R register int
    using namespace std;
    namespace Luitaryi {
    template<class I> inline I g(I& x) { x=0; register I f=1;
      register char ch; while(!isdigit(ch=getchar())) f=ch=='-'?-1:f;
      do x=x*10+(ch^48); while(isdigit(ch=getchar())); return x*=f;
    } const int N=30010,M=60010,Inf=0x3f3f3f3f;
    int n,m,K,rt,tot,cnt,size,sum,ans=-1,C; bool vis[N];
    int vr[N<<1],nxt[N<<1],fir[N],w[N<<1],sz[N],d[N],c[N],mx[N];
    int dis[N],buf[N],mem[N],q[N],q2[N];
    vector<pair<int,int> > e[N];
    inline void add(int u,int v,int ww) {
      vr[++cnt]=v,nxt[cnt]=fir[u],w[cnt]=ww,fir[u]=cnt;
      vr[++cnt]=u,nxt[cnt]=fir[v],w[cnt]=ww,fir[v]=cnt;
    }
    inline void spfa() { memset(d,0x3f,sizeof(d));
      queue<int>q; q.push(1),d[1]=0,vis[1]=true;
      while(q.size()) { R u=q.front(); q.pop(),vis[u]=false;
        for(R i=0,lim=e[u].size();i<lim;++i) { R v=e[u][i].first,w=e[u][i].second;
          if(d[v]>d[u]+w) {
            d[v]=d[u]+w; if(!vis[v]) vis[v]=true,q.push(v);
          }
        }
      } 
    }
    inline void dfs(int u) { vis[u]=true;
      sort(e[u].begin(),e[u].end());
      for(R i=0,lim=e[u].size();i<lim;++i) { R v=e[u][i].first,w=e[u][i].second;
        if(vis[v]||d[v]!=d[u]+w) continue;
        add(u,v,w); dfs(v);
      }
    }
    inline void getsz(int u,int fa) {
      sz[u]=1,mx[u]=0;
      for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
        if(v==fa||vis[v]) continue;
        getsz(v,u),sz[u]+=sz[v];
        mx[u]=max(mx[u],sz[v]);
      } mx[u]=max(mx[u],sum-sz[u]);
      if(mx[u]<mx[rt]) rt=u;
    }
    inline void getdis(int u,int fa) {
      q[++tot]=c[u],q2[tot]=d[u];
      for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
        if(v==fa||vis[v]) continue;
        c[v]=c[u]+1,d[v]=d[u]+w[i];
        if(c[v]<=K) getdis(v,u);
      }
    }
    inline void solve(int u,int fa) { vis[u]=true;
      buf[++size]=1,mem[1]=1,dis[1]=0;
      for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
        if(v==fa||vis[v]) continue;
        d[v]=w[i],c[v]=1,getdis(v,u);
        for(R i=1;i<=tot;++i) { 
          if(mem[K-q[i]]) {
            if(ans<q2[i]+dis[K-q[i]]) ans=q2[i]+dis[K-q[i]],C=mem[K-q[i]];
            else if(ans==q2[i]+dis[K-q[i]]) C+=mem[K-q[i]];
          }   
        } 
        for(R i=1;i<=tot;++i) 
          if(mem[q[i]+1]) {
            if(dis[q[i]+1]==q2[i]) ++mem[q[i]+1];
            else if(dis[q[i]+1]<q2[i]) mem[q[i]+1]=1,dis[q[i]+1]=q2[i];
          }
          else buf[++size]=q[i]+1,++mem[q[i]+1],dis[q[i]+1]=q2[i]; tot=0;
      } while(size) mem[buf[size]]=0,dis[buf[size]]=0,--size;
      for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
        if(v==fa||vis[v]) continue;
        sum=sz[v]; rt=0,mx[0]=n; getsz(v,u),getsz(rt,0),solve(rt,u);
      }
    }
    inline void main() { freopen("in.in","r",stdin);
      g(n),g(m),g(K); for(R i=1,u,v,w;i<=m;++i) 
        g(u),g(v),g(w),e[u].push_back(make_pair(v,w)),
        e[v].push_back(make_pair(u,w));
      spfa(),dfs(1); memset(vis,0,sizeof(vis));
      sum=n,mx[0]=Inf; getsz(1,-1),getsz(rt,-1);
      solve(rt,-1),printf("%d %d
    ",ans,C);
    }
    } signed main() {Luitaryi::main(); return 0;}
    

    2019.08.31
    69

  • 相关阅读:
    【MySQL】:利用DCL管理用户和控制权限
    【MySQL】:事务四大特性与隔离级别
    JDBC概述及编程步骤详解
    【MySQL】:多表查询
    【MySQL】:MySQL中四大约束
    MySQL解决DOS窗口乱码问题
    【MySQL】:分组查询where和having
    【MySQL】:利用DQL查询表中的数据
    【MySQL】:利用DML操作表中数据
    【MySQL】:利用DDL操作数据库、表
  • 原文地址:https://www.cnblogs.com/Jackpei/p/11437897.html
Copyright © 2011-2022 走看看