zoukankan      html  css  js  c++  java
  • POJ1741 tree 【点分治】

    Tree
    Time Limit: 1000MS   Memory Limit: 30000K
    Total Submissions: 25286   Accepted: 8421

    Description

    Give a tree with n vertices,each edge has a length(positive integer less than 1001). 
    Define dist(u,v)=The min distance between node u and v. 
    Give an integer k,for every pair (u,v) of vertices is called valid if and only if dist(u,v) not exceed k. 
    Write a program that will count how many pairs which are valid for a given tree. 

    Input

    The input contains several test cases. The first line of each test case contains two integers n, k. (n<=10000) The following n-1 lines each contains three integers u,v,l, which means there is an edge between node u and v of length l. 
    The last test case is followed by two zeros. 

    Output

    For each test case output the answer on a single line.

    Sample Input

    5 4
    1 2 3
    1 3 1
    1 4 2
    3 5 1
    0 0
    

    Sample Output

    8


    点分治

    点分治通常用以解决树上的分治问题,以点为界分治。【我做题还不够多,先不详细讲,之后再总结
    这道题要求所有d(u,v) <= k的对数,直接枚举肯定不行,我们先求出路径经过树上一点的路径数

    如何求通过一点的路径数?
    我们以该点为根并求出树中所有点到根的距离,再全部排序,用双指针的方法O(n)统计d[u] + d[v] <= k的对数ans1
    但是会将都在同一个子树,也就是不经过根的路径也算上,再对每一个子树算一遍ans2减去就好了
    就是ans1 - ∑ans2

    之后再向下分治,向每颗子树递归。

    为防止极端数据,我们每次求出重心为根
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define LL long long int
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define Redge(u) for (int k = head[u]; k != -1; k = edge[k].next)
    using namespace std;
    const int maxn = 10005,maxm = 40005,INF = 1000000000;
    inline int RD(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57) {out = (out << 1) + (out << 3) + c - '0'; c = getchar();}
    	return out * flag;
    }
    int N,K,vis[maxn],head[maxn],d[maxn],dep[maxn],nedge = 0,F[maxn],Siz[maxn],rt = 0,n,ans;
    struct EDGE{int to,w,next;}edge[maxm];
    inline void build(int u,int v,int w){
    	edge[nedge] = (EDGE){v,w,head[u]}; head[u] = nedge++;
    	edge[nedge] = (EDGE){u,w,head[v]}; head[v] = nedge++;
    }
    void getRT(int u,int fa){
    	int to; F[u] = 0; Siz[u] = 1;
    	Redge(u) if ((to = edge[k].to) != fa && !vis[to]){
    		getRT(to,u);
    		Siz[u] += Siz[to];
    		F[u] = max(F[u],Siz[to]);
    	}
    	F[u] = max(F[u],n - Siz[u]);
    	if (F[u] < F[rt]) rt = u;
    }
    void getdep(int u,int fa){
    	dep[++dep[0]] = d[u]; int to;
    	Redge(u) if (!vis[to = edge[k].to] && to != fa){
    		d[to] = d[u] + edge[k].w;
    		getdep(to,u);
    	}
    }
    int cal(int u,int D){
    	d[u] = D; dep[0] = 0;
    	getdep(u,0);
    	sort(dep + 1,dep + 1 + dep[0]);
    	int l = 1,r = dep[0],t = 0;
    	while (l < r)
    		if (dep[l] + dep[r] <= K) t += r - l++;
    		else r--;
    	return t;
    }
    void solve(int u){
    	ans += cal(u,0);
    	vis[u] = true; int to;
    	Redge(u) if (!vis[to = edge[k].to]){
    		ans -= cal(to,edge[k].w);
    		n = Siz[to]; rt = 0;
    		getRT(to,rt);
    		solve(rt);
    	}
    }
    int main(){
    	while (true){
    		memset(head,-1,sizeof(head));
    		memset(vis,0,sizeof(vis));
    		int a,b,w; N = RD(); K = RD(); ans = 0; rt = 0; nedge = 0;
    		if (!N) break;
    		REP(i,N - 1){
    			a = RD(); b = RD(); w = RD();
    			build(a,b,w);
    		}
    		n = N; F[0] = INF;
    		getRT(1,0);
    		solve(rt);
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    


  • 相关阅读:
    惊讶
    BLOG休假
    因考试得福
    Shape of My HeartSting !
    一个月的第一天了
    BLOG开张喽~~~
    该走了
    脏话
    EditText的属性
    游戏引擎
  • 原文地址:https://www.cnblogs.com/Mychael/p/8282793.html
Copyright © 2011-2022 走看看