zoukankan      html  css  js  c++  java
  • luogu 2993 [FJOI2014]最短路径树问题 Dijkstra+点分治

    挺简单的,但是给人一种把两个问题强行弄到一起的感觉. 

    十分不好写. 

    Code: 

    #include <queue> 
    #include <cstdio> 
    #include <vector>   
    #include <algorithm>  
    #define N 100007    
    #define ll long long 
    #define inf 1000000004  
    #define setIO(s) freopen(s".in","r",stdin)  
    using namespace std;    
    int K,n,m;  
    namespace tree 
    {  
    	ll answer; 
    	int edges,root,sn,maxdep,tl,best; 
    	int hd[N],to[N],nex[N],val[N]; 
    	int size[N],mx[N],vis[N],f[N],g[N],bu[N],cntf[N],cntg[N];    
    	void addedge(int u,int v,int c)
    	{ 
    		nex[++edges]=hd[u],hd[u]=edges,to[edges]=v,val[edges]=c;     
    	}
    	void getroot(int u,int ff) 
    	{
    		size[u]=1,mx[u]=0; 
    		for(int i=hd[u];i;i=nex[i]) 
    		{
    			int v=to[i]; 
    			if(!vis[v]&&v!=ff) 
    				getroot(v,u), size[u]+=size[v], mx[u]=max(mx[u], size[v]); 
    		} 
    		mx[u]=max(mx[u],sn-size[u]); 
    		if(mx[u]<mx[root]) root=u; 
    	}  
    	void dfs(int u,int ff,int depth,int p) 
    	{      
    		if(depth>=g[p]) 
    		{ 
    			if(depth==g[p]) ++cntg[p];    
    			else {
    				if(!g[p]) bu[++tl]=p;    
    				g[p]=depth, cntg[p]=1;   
    			}
    		}   
    		for(int i=hd[u];i;i=nex[i]) 
    		{
    			int v=to[i]; 
    			if(v==ff||vis[v]) continue;   
    			dfs(v,u,depth+val[i],p+1);   
    		}
    	}  
    	void calc(int u) 
    	{  
    		int i,j,cur=0;   
    		cntf[0]=1,tl=0;             
    		for(i=hd[u];i;i=nex[i]) 
    		{
    			int v=to[i]; 
    			if(vis[v]) 
    				continue;     
    			dfs(v,u,val[i],1);    
    			for(j=cur+1;j<=tl;++j)  
    			{  
    				if(K-1<bu[j]) continue;     
    				if(g[bu[j]]+f[K-bu[j]-1]==best) 
    				{ 
    					answer+=(ll)(cntg[bu[j]]*cntf[K-bu[j]-1]);   
    				}
    				else if(g[bu[j]]+f[K-bu[j]-1]>best) 
    				{ 
    					best=g[bu[j]]+f[K-bu[j]-1];       
    					answer=(ll)(cntg[bu[j]]*cntf[K-bu[j]-1]);   
    				}   
    			}    
    			for(j=cur+1;j<=tl;++j) 
    			{
    				if(g[bu[j]]==f[bu[j]]) cntf[bu[j]]+=cntg[bu[j]];  
    				else if(g[bu[j]]>f[bu[j]]) 
    				{
    					cntf[bu[j]]=cntg[bu[j]];  
    					f[bu[j]]=g[bu[j]]; 
    				}
    			} 
    			for(j=cur+1;j<=tl;++j) 
    				cntg[bu[j]]=g[bu[j]]=0;     
    			cur=tl;    
    		}      
    		for(i=1;i<=cur;++i) cntf[bu[i]]=cntg[bu[i]]=f[bu[i]]=g[bu[i]]=0;       
    	}
    	void solve(int u) 
    	{    
    		vis[u]=1; 
    		calc(u); 
    		for(int i=hd[u];i;i=nex[i]) 
    			if(!vis[to[i]]) 
    				sn=size[to[i]],root=0,getroot(to[i],u),solve(root);     
    	}  
    	int main() 
    	{  
    		root=0,mx[0]=inf,sn=n; 
    		getroot(1,0),solve(root);
    		printf("%d %lld
    ",best,answer);            
    		return 0; 
    	}
    }; 
    namespace Dijkstra 
    {    
    	int d[N],done[N],vis[N];    
    	struct Edge 
    	{
    		int to,val;  
    		Edge(int to=0,int val=0):to(to),val(val){}   
    	};  
    	bool cmp(Edge a,Edge b) 
    	{
    		return a.to<b.to; 
    	}
    	struct Node 
    	{
    		int u,dis; 
    		Node(int u=0,int dis=0):u(u),dis(dis){}    
    		bool operator<(Node a)const 
    		{
    			return a.dis<dis;    
    		}
    	};    
    	priority_queue<Node>q;    
    	vector<Edge>G[N];        
    	void add(int u,int v,int c) 
    	{
    		G[u].push_back(Edge(v,c));      
    	}   
    	void dfs(int u) 
    	{ 
    		vis[u]=1;    
    		for(int i=0;i<G[u].size();++i) 
    			if(!vis[G[u][i].to]&&d[u]+G[u][i].val==d[G[u][i].to]) 
    			{
    				vis[G[u][i].to]=1; 
    				tree::addedge(u,G[u][i].to,G[u][i].val);  
    				tree::addedge(G[u][i].to,u,G[u][i].val);       
    				dfs(G[u][i].to);       
    			}
    	}
    	void build_tree() 
    	{  
    		int i; 
    		for(i=0;i<=n;++i) d[i]=inf; 
    		q.push(Node(1,0)), d[1]=0; 
    	    while(!q.empty()) 
    	    {
    	    	Node e=q.top();q.pop(); 
    	    	int u=e.u;   
    	    	if(done[u]) continue; 
    	    	done[u]=1; 
    	    	for(i=0;i<G[u].size();++i) 
    	    	{
    	    		Edge h=G[u][i]; 
    	    		if(d[h.to]>d[u]+h.val) 
    	    		{
    	    			d[h.to]=d[u]+h.val; 
    	    			q.push(Node(h.to,d[h.to]));             
    	    		}
    	    	}
    	    }   
    	    for(i=1;i<=n;++i) sort(G[i].begin(),G[i].end(),cmp);  
    	    dfs(1);    
    	}
    }; 
    int main() 
    {
    	int i,j; 
    	// setIO("input");        
    	scanf("%d%d%d",&n,&m,&K);      
    	for(i=1;i<=m;++i) 
    	{
    		int a,b,c; 
    		scanf("%d%d%d",&a,&b,&c);
    		Dijkstra::add(a,b,c); 
    		Dijkstra::add(b,a,c);      
    	} 
    	Dijkstra::build_tree();    
    	tree::main();        
    	return 0; 
    }
    

      

  • 相关阅读:
    抖动代码
    WSAWaitForMultipleEvents()
    udp 不需要 listen
    WSAEventSelect
    C++ Win32控制台应用程序捕捉关闭事件
    玩转Win32开发(2):完整的开发流程
    win32线程池代码(WinApi/C++)
    又线程类封装
    Win2 Socket(套接字)相关 API
    Win32函数Sleep的精度测试
  • 原文地址:https://www.cnblogs.com/guangheli/p/11447564.html
Copyright © 2011-2022 走看看