HDU 5102 树分治

The K-th Distance

Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 202    Accepted Submission(s): 50


Problem Description
Given a tree, which has n node in total. Define the distance between two node u and v is the number of edge on their unique route. So we can have n(n-1)/2 numbers for all the distance, then sort the numbers in ascending order. The task is to output the sum of the first K numbers.
 

Input
There are several cases, first is the number of cases T. (There are most twenty cases).
For each case, the first line contain two integer n and K ( 2n100000,0Kmin(n(n1)/2,106) ). In following there are n-1 lines. Each line has two integer u , v. indicate that there is an edge between node u and v.
 

Output
For each case output the answer.
 

Sample Input
 
   
2 3 3 1 2 2 3 5 7 1 2 1 3 2 4 2 5
 

Sample Output
 
   
4 10
 

Source
BestCoder Round #17


给定一个n个节点的树,求路径长度前k大的所有路径和。

题解方法:把所有边(u,v) 以及(v,u)放入一个队列,队列每弹出一个元素(u,v),对于所有与u相邻的点w,如果w!=v,就把(w,u)入队。这样就能一个一个生成前K小的距离。注意到每条边实际上会入队两次,只要把K翻倍且把ans除2即可,时间复杂度为O(n+K)

由于思路简单,就懒得写代码了,直接抄了yyn代码:

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std ;

typedef long long LL ;

#define rep( i , a , b ) for ( int i = ( a ) ; i <  ( b ) ; ++ i )
#define For( i , a , b ) for ( int i = ( a ) ; i <= ( b ) ; ++ i )
#define rev( i , a , b ) for ( int i = ( a ) ; i >= ( b ) ; -- i )
#define clr( a , x ) memset ( a , x , sizeof a )

const int MAXN = 100005 ;
const int MAXE = 200005 ;

struct Node {
    int v , p , d ;
    Node () {}
    Node ( int v , int p , int d ) : v ( v ) , p ( p ) , d ( d ) {}
} ;

struct Edge {
    int v , n ;
    Edge () {}
    Edge ( int v , int n ) : v ( v ) , n ( n ) {}
} ;

Node Q[3000005] ;
Edge E[MAXE] ;
int H[MAXN] , cntE ;
int head , tail ;
LL ans ;
int n , k ;

void clear () {
    ans = 0 ;
    cntE = 0 ;
    clr ( H , -1 ) ;
}

void addedge ( int u , int v ) {
    E[cntE] = Edge ( v , H[u] ) ;
    H[u] = cntE ++ ;
}

void bfs () {
    int cnt = 0 ;
    head = tail = 0 ;
    For ( i , 1 , n ) Q[tail ++] = Node ( i , 0 , 0 ) ;
    while ( head != tail ) {
        Node x = Q[head ++] ;
        int u = x.v , p = x.p ;
        for ( int i = H[u] ; ~i ; i = E[i].n ) {
            int v = E[i].v ;
            if ( v != p ) {
                Q[tail ++] = Node ( v , u , x.d + 1 ) ;
                ans += x.d + 1 ;
                //printf ( "%d->%d %d %d\n" , u , v , cnt , x.d + 1 ) ;
                ++ cnt ;
                if ( cnt == k ) return ;
            }
        }
    }
}

void solve () {
    int u , v ;
    clear () ;
    scanf ( "%d%d" , &n , &k ) ;
    k *= 2 ;
    rep ( i , 1 , n ) {
        scanf ( "%d%d" , &u , &v ) ;
        addedge ( u , v ) ;
        addedge ( v , u ) ;
    }
    bfs () ;
    printf ( "%I64d\n" , ans / 2 ) ;
}

int main () {
    int T ;
    scanf ( "%d" , &T ) ;
    while ( T -- ) solve () ;
    return 0 ;
}

还有一种方法,按照树分治考虑,由于k最大为1000000,那么第k长的路径长度必然数据不是很大,我们可以估计一个上限,然后按照树分治的做法,统计每一个长度的方案数,对于每一个分治重心,枚举每一颗子树,然后统计方案数,最后扫描一遍就行了。

代码:

/* ***********************************************
Author :rabbit
Created Time :2014/11/9 12:03:22
File Name :H.cpp
************************************************ */
#pragma comment(linker, "/STACK:102400000,102400000")
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
#define INF 0x3f3f3f3f
#define eps 1e-8
#define pi acos(-1.0)
typedef long long ll;
const int maxn=100100;
int head[maxn],tol;
int size[maxn],vis[maxn],fa[maxn],que[maxn];
int num[maxn],ans[maxn];
int maxd,TT;
struct Edge{
	int next,to;
}edge[3*maxn];
inline void addedge(int u,int v){
	edge[tol].to=v;
	edge[tol].next=head[u];
	head[u]=tol++;
}
inline int getroot(int u){
	int Min=maxn,root=0;
	int l,r;
	que[l=r=1]=u;fa[u]=u;
	for(;l<=r;l++)
		for(int i=head[que[l]];i!=-1;i=edge[i].next){
			int v=edge[i].to;
			if(v==fa[que[l]]||vis[v]==TT)continue;
			que[++r]=v;
			fa[v]=que[l];
		}
	for(l--;l;l--){
		int x=que[l],Max=0;
		size[x]=1;
		for(int i=head[x];i!=-1;i=edge[i].next){
			int v=edge[i].to;
			if(v==fa[x]||vis[v]==TT)continue;
			Max=max(Max,size[v]);
			size[x]+=size[v];
		}
		Max=max(Max,r-size[x]);
		if(Maxmaxd)continue;
				dis[v]=dis[x]+1;
				fa[v]=x;
				que[++r]=v;
			}
		}
		for(int j=0;j>T;
	 memset(vis,0,sizeof(vis));
	 while(T--){
		 scanf("%d%d",&n,&k);
		 maxd=min(k/n+50,k);
		 memset(head,-1,sizeof(head));tol=0;
		 memset(num,0,sizeof(num));
		 memset(ans,0, sizeof(ans));
		 TT++;
		 for(int i=1;i=k){
				 sum+=(ll)k*i;
				 break;
			 }
			 k-=ans[i];
			 sum+=(ll)ans[i]*i;
		 }
		 printf("%I64d\n",sum);
	 }
     return 0;
}


你可能感兴趣的:(数据结构,基础图论)