zoukankan      html  css  js  c++  java
  • 【bzoj4016】 FJOI2014—最短路径树问题

    http://www.lydsy.com/JudgeOnline/problem.php?id=4016 (题目链接)

    题意

      给出一张无向图,求出它的最小路径树,然后求最小路径树上节点数为${K}$的最长路径,并求出这样的路径有多少条。

    Solution

      mdzz看错题了,以为求路径条数的时候对节点个数没有要求。。

      抠最小路径树有点恶心,还对字典序有要求,参见了DaD3zZ的方法,枚举边,将符合距离条件的连边,然后dfs,优先字典序小的。

      至于点分治,就是两个数组搞一搞,挺简单的一个统计。

    细节

      不要乱用memset,不然复杂度就不对了。

      这种比较长的程序写在namespace或者结构体里面会比较清晰吧。

    代码

    // bzoj4016
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<vector>
    #include<cmath>
    #include<queue>
    #include<map>
    #define LL long long
    #define inf 1ll<<30
    #define Pi acos(-1.0)
    #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
    using namespace std;
    
    const int maxn=30010,maxm=60010;
    int vis[maxn],deep[maxn],f[maxn],size[maxn],head[maxn];
    int n,m,K,cnt,sum,Dargen;
    int ans1;LL ans2;
    
    struct edge {int from,to,next,w;}e[maxm<<1];
    
    namespace Prepare {
    	int dis[maxn];
    	vector<int> v[maxn];
        struct data {
    		int num,w;
    		friend bool operator < (const data a,const data b) {
    			return a.w>b.w;
    		}
    	};
    
    	void link(int u,int v,int w) {
    		e[++cnt]=(edge){u,v,head[u],w};head[u]=cnt;
    		e[++cnt]=(edge){v,u,head[v],w};head[v]=cnt;
    	}
    	void Dijkstra() {
    		priority_queue<data> q;
    		for (int i=1;i<=n;i++) dis[i]=inf;
    		q.push((data){1,0});dis[1]=0;
    		while (!q.empty()) {
    			data x=q.top();q.pop();
    			if (vis[x.num]) continue;
    			vis[x.num]=1;
    			for (int i=head[x.num];i;i=e[i].next)
    				if (!vis[e[i].to] && dis[e[i].to]>x.w+e[i].w) {
    					dis[e[i].to]=x.w+e[i].w;
    					q.push((data){e[i].to,dis[e[i].to]});
    				}
    		}
    		for (int i=1;i<=cnt;i++) {
    			int uu=e[i].from,vv=e[i].to,ww=e[i].w;
    			if (dis[uu]+ww==dis[vv]) v[uu].push_back(vv);
    		}
    	}
    	void build(int x) {
    		vis[x]=1;
    		sort(v[x].begin(),v[x].end());
    		int l=v[x].size();
    		for (int i=0;i<l;i++) if (!vis[v[x][i]]) {
    				link(x,v[x][i],dis[v[x][i]]-dis[x]);
    				build(v[x][i]);
    			}
    	}
    }
    
    namespace NodeDivide {
    	int D[maxn],d[maxn],cntd[maxn],cntD[maxn];
    
    	void caldargen(int x,int fa) {
    		size[x]=1;f[x]=0;
    		for (int i=head[x];i;i=e[i].next) if (!vis[e[i].to] && e[i].to!=fa) {
    				caldargen(e[i].to,x);
    				size[x]+=size[e[i].to];
    				f[x]=max(f[x],size[e[i].to]);
    			}
    		f[x]=max(f[x],sum-size[x]);
    		if (f[x]<f[Dargen]) Dargen=x;
    	}
    	void caldeep(int x,int fa,int l) {
    		if (d[deep[x]]<l) d[deep[x]]=l,cntd[deep[x]]=1;
    		else if (d[deep[x]]==l) cntd[deep[x]]++;
    		for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa && !vis[e[i].to]) {
    				deep[e[i].to]=deep[x]+1;
    				caldeep(e[i].to,x,l+e[i].w);
    			}
    	}
    	void work(int x) {
    		vis[x]=1;
    		for (int i=head[x];i;i=e[i].next) if (!vis[e[i].to]) {
    				deep[e[i].to]=1;
    				caldeep(e[i].to,0,e[i].w);
    				for (int j=1;d[j] && j<K;j++) {
    					if (ans1<D[K-1-j]+d[j]) {
    						ans1=D[K-1-j]+d[j];
    						ans2=(LL)cntD[K-1-j]*cntd[j];
    					}
    					else if (ans1==D[K-1-j]+d[j]) ans2+=(LL)cntD[K-1-j]*cntd[j];
    				}
    				for (int j=1;d[j];j++) {
    					if (D[j]<d[j]) D[j]=d[j],cntD[j]=cntd[j];
    					else if (D[j]==d[j]) cntD[j]+=cntd[j];
    					d[j]=cntd[j]=0;
    				}
    			}
    		for (int i=1;D[i];i++) D[i]=cntD[i]=0;
    		for (int i=head[x];i;i=e[i].next) if (!vis[e[i].to] && size[e[i].to]>=K) {
    				Dargen=0;sum=size[e[i].to];
    				caldargen(e[i].to,0);
    				work(Dargen);
    			}
    	}
    	void Init() {
    		memset(vis,0,sizeof(vis));
    		f[0]=inf;sum=n;cntD[0]=1;
    		Dargen=0;caldargen(1,0);
    		work(Dargen);
    	}
    }
    
    int main() {
    	scanf("%d%d%d",&n,&m,&K);
    	for (int u,v,w,i=1;i<=m;i++) {
    		scanf("%d%d%d",&u,&v,&w);
    		Prepare::link(u,v,w);
    	}
    	Prepare::Dijkstra();
    	memset(head,0,sizeof(head));
    	memset(vis,0,sizeof(vis));
    	cnt=0;
    	Prepare::build(1);
    	NodeDivide::Init();
    	printf("%d %lld",ans1,ans2);
    	return 0;
    }
    
  • 相关阅读:
    JVM1
    JVM
    安卓权威编程指南 -笔记(19章 使用SoundPool播放音频)
    安卓权威编程指南 -笔记(18章 处理assets)
    安卓权威编程指南 挑战练习 16章
    安卓权威编程指南 -挑战练习 15章。
    安卓权威编程指南 挑战练习 13.8 用于RecyclerView的空视图
    安卓权威编程指南 挑战练习13.7-优化字符串资源显示
    关于List比较好玩的操作
    安卓权威编程指南 挑战练习13.6 14.8
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/6355498.html
Copyright © 2011-2022 走看看