POJ 1987 Distance Statistics 树分治

Distance Statistics

Description

Frustrated at the number of distance queries required to find a reasonable route for his cow marathon, FJ decides to ask queries from which he can learn more information. Specifically, he supplies an integer K (1 <= K <= 1,000,000,000) and wants to know how many pairs of farms lie at a distance at most K from each other (distance is measured in terms of the length of road required to travel from one farm to another). Please only count pairs of distinct farms (i.e. do not count pairs such as (farm #5, farm #5) in your answer).

Input

* Lines 1 ..M+1: Same input format as in "Navigation Nightmare"

* Line M+2: A single integer, K.

Output

* Line 1: The number of pairs of farms that are at a distance of at most K from each-other.

Sample Input

7 6
1 6 13 E
6 3 9 E
3 5 7 S
4 1 3 N
2 4 20 W
4 7 2 S
10

Sample Output

5

Hint

There are 5 roads with length smaller or equal than 10, namely 1-4 (3), 4-7 (2), 1-7 (5), 3-5 (7) and 3-6 (9).

题解:

  POJ 1741

  http://www.cnblogs.com/zxhl/p/5692688.html

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
const int N = 4e4+20, M = 1e2+10, mod = 1e9+7, inf = 1e9+1000;
typedef long long ll;

int ans, n,m,root , t = 1,K,siz[N],head[N],f[N],deep[N],d[N],allnode,vis[N];
struct edg{int to,next,v,w;}e[N * 4];
void add(int u,int v,int w) {e[t].to=v;e[t].v=w;e[t].next=head[u];head[u]=t++;}

void getroot(int x,int fa) {
    siz[x] = 1;
    f[x] = 0;
    for(int i=head[x];i;i=e[i].next) {
        int to = e[i].to;
        if(to == fa || vis[to]) continue;
        getroot(to,x);
        siz[x] += siz[to];
        f[x] = max(f[x] , siz[to]);
    }
    f[x] = max(f[x] , allnode - siz[x]);
    if(f[x] < f[root]) root = x;
}
void getdeep(int x,int fa) {
    if(d[x] <= K) deep[++deep[0]]=d[x];
    for(int i=head[x];i;i=e[i].next) {
        int to = e[i].to;
        if(to == fa || vis[to]) continue;
        d[to] = d[x] + e[i].v;
        getdeep(to,x);
    }
}
int cal(int x,int now) {
    d[x]=now;deep[0] = 0;
    getdeep(x,0);
    sort(deep+1,deep+deep[0]+1);
    int all = 0;
    for(int l=1,r=deep[0];l<r;) {
        if(deep[l]+deep[r] <= K) {all+=r-l;l++;}
        else r--;
    }
    return all;
}
void work(int x) {
    ans+=cal(x,0);
    vis[x] = 1;
    for(int i=head[x];i;i=e[i].next) {
        int to = e[i].to;
        if(vis[to]) continue;
        ans-=cal(to,e[i].v);
        allnode = siz[to];
        root = 0;
        getroot(to,root);
        work(root);
    }
}
void init()
{
    memset(head,0,sizeof(head));
    t = 1;
    ans = root = 0;
    memset(vis,0,sizeof(vis));
}
int main()
{
    while(~scanf("%d%d",&n,&m)) {
        init();
        for(int i=1;i<n;i++) {
            int a,b,c;char ch[2];
            scanf("%d%d%d%s",&a,&b,&c,ch);
            add(a,b,c) , add(b,a,c);
        }
        scanf("%d",&K);
        allnode=n;f[0]=inf;
        getroot(1,0);
        work(root);
        printf("%d\n",ans);
    }

}
时间: 2024-10-19 07:54:00

POJ 1987 Distance Statistics 树分治的相关文章

POJ 1987 Distance Statistics (树上点分治)

题目地址:POJ 1987 点分治模板题,跟POJ 1741几乎一样,.. 代码如下: #include <iostream> #include <string.h> #include <math.h> #include <queue> #include <algorithm> #include <stdlib.h> #include <map> #include <set> #include <stdi

POJ - 1987 Distance Statistics 树上的分治

题目大意:和poj 1741的那题和类似,求树上节点之间的距离小于等于k的节点对有多少对 解题思路:具体可参考:<分治算法在树的路径问题中的应用--漆子超> 给这题的输入坑了,注意输入,不然会超时 #include<cstdio> #include<vector> #include<algorithm> using namespace std; #define maxn 40010 int vis[maxn], Sum[maxn], d[maxn], dp[

POJ 1741 Tree ——(树分治)

思路参考于:http://blog.csdn.net/yang_7_46/article/details/9966455,不再赘述. 复杂度:找树的重心然后分治复杂度为logn,每次对距离数组dep排序复杂度为nlogn,而找重心的复杂度为dfs的复杂度--O(n),因此总的复杂度为O(nlognlogn). 因为第一次写树分治,留个代码: 1 #include <stdio.h> 2 #include <algorithm> 3 #include <string.h>

POJ 1741 Tree(树分治|ltc男人八题)

 题意:求树上距离小于等于K的点对有多少个. 思路:这道题很容易想到树分治,对于当前的根节点来说,任意两个结点之间要么过根结点,要么在一棵子树中. 那么我们dfs一次求出所有点到根结点的距离,然后用o(n)的时间判定有多少节点对符合,(判断方法稍后说) 但是这样有很多在一颗子树中的节点对我们会求重复,我们需要减去在一棵子树中结点对小于等于k的数量,也就是说,我们这一步求的是在不同子树中距离小于等于k的节点对的个数. 接下来说判定方法,将每个点到根结点的距离排序,用两个指针指向队首和队尾,当结

POJ 1987 BZOJ 3365 Distance Statistics 树的分治(点分治)

题目大意:(同poj1741,刷一赠一系列) CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 40010 #define INF 0x3f3f3f3f using namespace std; int points,edges,k; int head[MAX],total; int next[MAX <<

BZOJ 3365 Distance Statistics 树的点分治

题目大意:同POJ1741 链接:http://blog.csdn.net/popoqqq/article/details/39959803 和POJ1741一样的题,土豪题,POJ有道一样的题,做完1741可以水水 我会告诉你我直接改了下上题的代码么0.0 数据范围4W 距离最大1000 不会爆INT 放心写吧 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm>

poj 1741 楼教主男人八题之一:树分治

http://poj.org/problem?id=1741 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

poj 1744 tree 树分治

Tree Time Limit: 1000MS   Memory Limit: 30000K       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 ve

POJ 1741 树分治

题目链接[http://poj.org/problem?id=1741] 题意: 给出一颗树,然后寻找点对(u,v)&&dis[u][v] < k的对数. 题解: 这是一个很经典的树分治的题.假设我们选择了一个参考点u,那么对于不同的点对(u,v),(u , v)之间的路径有两种情况,经过点u,和不经过点u,加入我算出了没有经过点u的对数,然后把经过点u的加起来就是答案了,很简单,这就是分治的思想.具体看代码. #include<cstdio> #include<c