• bzoj4016: [FJOI2014]最短路径树问题


    题目链接

    bzoj4016: [FJOI2014]最短路径树问题

    题解

    对于建树
    dij建出最短路图
    在最短路图上dfs,先走字典序最小的可达点

    得到最短路树
    然后就是经典的点分治了
    维护每个深度的最远距离合并就好了

    代码

    #include<queue> 
    #include<vector> 
    #include<cstdio> 
    #include<cstring> 
    #include<algorithm> 
    
    const int maxn  = 30007; 
    #define mp std::make_pair
    
    #define pr std::pair<int,int>
    
    std::vector<int>v[maxn];
    #define INF 0x3f3f3f3f 
    
    int hh[maxn] , tt[maxn << 2]  , ww[maxn << 2] , nn[maxn << 2] , cc = 1 , vv[maxn] , Dis[maxn] , uu[maxn];
    int n , k , head[maxn] , to[maxn << 1] , w[maxn << 1] , next[maxn << 1] , cnt;
    int vis[maxn] , root , sum , son[maxn] , F[maxn] ,f[maxn],g[maxn] ,Depdis[maxn] ,sg[maxn],md,deep[maxn] , dis[maxn] , ans , num;
    
    void Add(int x , int y , int z) {  tt[++cc] = y,ww[cc] = z,nn[cc] = hh[x],hh[x] = cc; } 
    void add_edge(int x , int y , int z) {  to[++cnt] = y,w[cnt] = z,next[cnt] = head[x],head[x] = cnt; } 
    
    std::priority_queue<pr> q;  
    void dijkstra() {  
        memset(Dis,0x3f,sizeof(Dis));  
        Dis[1] = 0 , q.push(mp(0 , 1));  
        while(!q.empty()) { 
            int x = q.top().second;q.pop();  
            if(vv[x]) continue;  
            vv[x] = 1;  
            for(int i = hh[x];i;i = nn[i])  
                if(Dis[x] == Dis[tt[i]] + ww[i])  
                    v[tt[i]].push_back(i ^ 1);  
            for(int i = hh[x] ; i ; i = nn[i]) 
                if(Dis[tt[i]] > Dis[x] + ww[i])  
                    Dis[tt[i]] = Dis[x] + ww[i] , q.push(mp(-Dis[tt[i]] , tt[i]));  
        } 
    } 
    inline bool cmp(int a ,int b) { return tt[a] < tt[b]; }  
     
    void dfs(int x)  { 
        std::sort(v[x].begin(),v[x].end(),cmp); 
        for(int i = 0;i < v[x].size();i ++ ) 
            if(!uu[tt[v[x][i]]]) { 
                uu[tt[v[x][i]]] = 1; 
    			add_edge(x,tt[v[x][i]],ww[v[x][i]]); 
    			add_edge(tt[v[x][i]],x,ww[v[x][i]]); 
    			dfs(tt[v[x][i]]); 
    	} 
    } 
    void getroot(int x,int fa) { 
        F[x] = 0,son[x] = 1;
        for(int i = head[x] ;i;i = next[i])
            if(!vis[to[i]] && to[i] != fa)
                getroot(to[i],x),son[x] += son[to[i]],F[x] = std::max(F[x],son[to[i]]); 
        F[x] = std::max(F[x] , sum - son[x]); 
        if(F[x] < F[root]) root = x;
    } 
    void getdeep(int x,int fa) { 
        for(int i = head[x] ; i ; i = next[i]) { 
            if(!vis[to[i]] && to[i] != fa) { 
                deep[to[i]] = deep[x] + 1,dis[to[i]] = dis[x] + w[i],md = std::max(md,deep[to[i]]); 
                if(dis[to[i]] > f[deep[to[i]]]) f[deep[to[i]]] = dis[to[i]],Depdis[deep[to[i]]] = 1; 
                else if(dis[to[i]] == f[deep[to[i]]]) Depdis[deep[to[i]]] ++ ; 
                getdeep(to[i],x); 
            } 
        } 
    } 
    void solve(int x,int sm = 0) { 
        vis[x] = 1;  
        for(int i = head[x] ; i ; i = next[i]) {  
            if(!vis[to[i]]) {  
                md = deep[to[i]] = 1,dis[to[i]] = w[i],f[1] = w[i],Depdis[1] = 1,getdeep(to[i],x);  
                for(int j = 1;j <= md && j <= k;j ++ ) {  
                    if(ans < f[j] + g[k - j]) ans = f[j] + g[k - j],num = Depdis[j] * sg[k - j];  
                    else if(ans == f[j] + g[k - j])num += Depdis[j] * sg[k - j];  
                }  
                for(int j = 1;j <= md && j <= k;j ++ ) {  
                    if(g[j] < f[j]) g[j] = f[j] , sg[j] = Depdis[j]; 
                    else if(g[j] == f[j]) sg[j] += Depdis[j]; 
                } 
                for(int j = 1;j <= md;j ++ ) f[j] = -INF , Depdis[j] = 0; 
                sm = std::max(sm,md); 
            } 
        } 
        for(int i = 1;i <= sm && i <= k;i ++ ) g[i] = -INF , sg[i] = 0; 
        for(int i = head[x];i;i = next[i])
            if(!vis[to[i]]) { 
                root = 0; 
    			sm = son[to[i]];  
    			getroot(to[i] , x); 
    			solve(root); 
    		} 
    } 
    int main() { 
        int m;  
        scanf("%d%d%d",&n,&m,&k); 
    	k -- ;
        for(int x,y,z,i = 1;i <= m ;i ++) scanf("%d%d%d",&x,&y,&z),Add(x,y,z),Add(y,x,z); 
        dijkstra(),uu[1] = 1,dfs(1); 
    	memset(f,0xc0,sizeof(f)) ; memset(g,0xc0,sizeof(g)),g[0] = 0,sg[0] = 1; 
        F[0] = INF,sum = n;  
    	getroot(1,0);  
    	solve(root); 
        printf("%d %d
    ", ans,num); 
        return 0; 
    } 
    
  • 相关阅读:
    资深工程师为何否定这种单例模式
    C#经典面试题及答案【20090210更新】
    难道SQL的子查询就是鸡肋吗?
    转:WCF基础知识问与答
    针对分析单点登录(流程图与数据安全)提出的问题及解决方案
    老生常谈:装饰者模式
    我对IDisposable接口的理解
    log4net日志组件经验分享
    老生常谈:工厂模式兄弟姐妹
    探讨高访问量网站优化方案(从图片角度)
  • 原文地址:https://www.cnblogs.com/sssy/p/9439725.html
Copyright © 2020-2023  润新知