zoukankan      html  css  js  c++  java
  • HDU4871 Shortest-path tree(点分治)

    题目

    题面

    大意是给你一个图,要你构建出一棵最短路树,再询问经过k个点的最长路径长度以及最长路径条数。

    思路

    点分治。
    点分治的思路是这样的:
    对于一个点(x)而言,对答案有影响的路径要么经过点(x)要么不经过,利用这点进行分治。
    点分治首先要找出一个重心。重心是指以该点为根所有的子树中sz最大的最小。
    然后,对于每一棵子树进行处理,统计答案(点分治题目不同的地方就在这,其它都是板子)
    之后再递归进重心的子树中处理。

    对于一个根来说,如果统计答案的复杂度是(O(n)),那么总的复杂度就是(O(nlogn)).

    代码

    #include<bits/stdc++.h>
    #define M 30005
    #define clr(x,y) memset(x,y,sizeof(x))
    using namespace std;
    int T,n,m,K;
    int g[M],tt;
    int ansa=0,ansc=0;//最长路,最长路的种数 
    struct Node{
    	int to,co;
    	bool operator < (const Node& res) const{
    		return to<res.to;	
    	}
    };
    vector<Node>G[M]; 
    struct edge{
    	int nxt,to,co;	
    }H[M<<1];
    void add(int a,int b,int c){
    	H[++tt]=(edge){g[a],b,c};
    	g[a]=tt;
    }
    struct node{
    	int x,ds;
    	bool operator < (const node& res) const{
    		return ds>res.ds;	
    	}
    };
    priority_queue<node>Q;
    int dis[M];
    bool vis[M];
    void Dij(){
    	clr(dis,0x3f);clr(vis,0);
    	dis[1]=0;
    	Q.push((node){1,0});
    	while(!Q.empty()){
    		node e=Q.top();Q.pop();
    		if(vis[e.x])continue;vis[e.x]=1;
    		for(int i=0;i<(int)G[e.x].size();i++){
    			int u=G[e.x][i].to,v=G[e.x][i].co;
    			if(dis[u]>dis[e.x]+v){
    				dis[u]=dis[e.x]+v;
    				Q.push((node){u,dis[u]});	
    			}
    		}
    	}
    }
    bool solved[M];
    int sz[M],ttot;
    void dfs(int x,int f,int ds){//构造树 
    	for(int i=0;i<(int)G[x].size();i++){
    		int u=G[x][i].to,v=G[x][i].co;
    		if(u==f||vis[u]||ds+v>dis[u])continue;
    		vis[u]=1;
    		add(u,x,v);add(x,u,v);
    		dfs(u,x,ds+v);
    	}
    }
    int mi=1e9,zx=1;
    void dfs_zx(int x,int f){//寻找重心 
    	sz[x]=1;int mm=0;
    	for(int i=g[x];i;i=H[i].nxt){
    		int u=H[i].to;
    		if(u==f||solved[u])continue;
    		dfs_zx(u,x);
    		sz[x]+=sz[u];
    		mm=max(mm,sz[u]);
    	}
    	mm=max(mm,ttot-sz[x]);
    	if(mm<mi)mi=mm,zx=x;
    }
    void find_zx(int rt){
    	mi=1e9,zx=1;
    	dfs_zx(rt,0);
    }
    void getans(int x,int y){
    	if(x>ansa)ansa=x,ansc=y;
    	else if(x==ansa)ansc+=y;
    }
    int mx[M],mn[M];
    int num[M],siz=0;
    void dfs_ans(int x,int f,int ds,int c){
    	dis[++siz]=ds;num[siz]=c;
    	for(int i=g[x];i;i=H[i].nxt){
    		int u=H[i].to,v=H[i].co;
    		if(solved[u]||u==f)continue;
    		dfs_ans(u,x,ds+v,c+1);	
    	}
    }
    void solve(int rt){
    	find_zx(rt);
    	solved[zx]=1;
    	for(int i=0;i<=K;i++)mx[i]=mn[i]=0;mn[0]=1;
    	for(int i=g[zx];i;i=H[i].nxt){
    		int u=H[i].to,v=H[i].co;
    		if(solved[u])continue;
    		siz=0;
    		dfs_ans(u,zx,v,1); 
    		for(int j=1;j<=siz;j++){
    			if(num[j]>=K)continue;
    			int tmp=K-1-num[j];
    			getans(mx[tmp]+dis[j],mn[tmp]);
    		}
    		for(int j=1;j<=siz;j++){
    			if(num[j]>=K)continue;
    			if(dis[j]>mx[num[j]]){
    				mx[num[j]]=dis[j];
    				mn[num[j]]=1;
    			}
    			else if(dis[j]==mx[num[j]])mn[num[j]]++;
    		}
    	}
    	ttot--;
    	for(int i=g[zx];i;i=H[i].nxt){
    		int u=H[i].to;
    		if(solved[u])continue;
    		solve(u);
    	}
    }
    int main(){
    	cin>>T;
    	while(T--){
    		clr(g,0);clr(solved,0);tt=ansa=ansc=0;
    		scanf("%d%d%d",&n,&m,&K);ttot=n;
    		for(int i=1;i<=n;i++)G[i].clear(); 
    		for(int i=1,a,b,c;i<=m;i++){
    			scanf("%d%d%d",&a,&b,&c);
    			G[a].push_back((Node){b,c});
    			G[b].push_back((Node){a,c});
    		}
    		for(int i=1;i<=n;i++)sort(G[i].begin(),G[i].end()); 
    		Dij();
    		clr(vis,0);dfs(1,0,0);
    		solve(1);
    		printf("%d %d
    ",ansa,ansc);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Linux学习总结(16)——CentOS 下 Nginx + Tomcat 配置负载均衡
    photo的复数是photos
    APUE1.11:系统调用 库函数
    Linux的man手册共有以下几个章节
    [关于宝宝的一些网上摘抄]
    ZT-Android深入浅出之Binder机 制
    jclass和jobject的迷惑
    ZT JAVA WeakReference
    ZT————pull push mode
    看了xici有写给孩子的信,maybe我也要写给孩子一些东西了
  • 原文地址:https://www.cnblogs.com/zryabc/p/10357173.html
Copyright © 2011-2022 走看看