Tree 点分治

Posted dongdong25800

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Tree 点分治相关的知识,希望对你有一定的参考价值。

 

 

题意:给一颗树,n个点,n-1条边,问有多少对点满足两点之间的距离小于k。码一道题

思路:设这个树的根为p,那么点对(x,y)分为过p点或者在p的子树部分,我们将点对按照所过的根节点进行划分成子问题处理,对于每个以p为根的子树,对于这个树,我们求d数组记录点到根的距离,b数组记录点所在根哪个子节点,之后用a数组记录节点,并把a数组按d排序,之后就可以通过双指针扫描求满足条件点对的个数。

 

//Author:XuHt
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 10006;
int n, k, s[N], Ans;
bool v[N], w[N];
int Head[N], Edge[N<<1], Leng[N<<1], Next[N<<1], t;
int ans, pos;
int d[N], b[N], a[N], tot, cnt[N];

void dfs_find(int S, int x) 
    v[x] = 1;
    s[x] = 1;
    int max_part = 0;
    for (int i = Head[x]; i; i = Next[i]) 
        int y = Edge[i];
        if (v[y] || w[y]) continue;
        dfs_find(S, y);
        s[x] += s[y];
        max_part = max(max_part, s[y]);
    
    max_part = max(max_part, S - s[x]);
    if (max_part < ans) 
        ans = max_part;
        pos = x;
    


void dfs(int x) 
    v[x] = 1;
    for (int i = Head[x]; i; i = Next[i]) 
        int y = Edge[i], z = Leng[i];
        if (v[y] || w[y]) continue;
        ++cnt[b[a[++tot]=y]=b[x]];
        d[y] = d[x] + z;
        dfs(y);
    


bool cmp(int i, int j) 
    return d[i] < d[j];


void work(int S, int x) 
    memset(v, 0, sizeof(v));
    ans = S;
    dfs_find(S, x);
    memset(d, 0, sizeof(d));
    memset(cnt, 0, sizeof(cnt));
    memset(v, 0, sizeof(v));
    w[a[tot=1]=b[pos]=pos] = 1;
    ++cnt[pos];
    for (int i = Head[pos]; i; i = Next[i]) 
        int y = Edge[i], z = Leng[i];
        if (v[y] || w[y]) continue;
        ++cnt[a[++tot]=b[y]=y];
        d[y] = z;
        dfs(y);
    
    sort(a + 1, a + tot + 1, cmp);
    int l = 1, r = tot;
    --cnt[b[a[1]]];
    while (l < r) 
        while (d[a[l]] + d[a[r]] > k) --cnt[b[a[r--]]];
        Ans += r - l - cnt[b[a[l]]];
        --cnt[b[a[++l]]];
    
    int now = pos;
    for (int i = Head[now]; i; i = Next[i]) 
        int y = Edge[i];
        if (w[y]) continue;
        work(s[y], y);
    


void add(int x, int y, int z) 
    Edge[++t] = y;
    Leng[t] = z;
    Next[t] = Head[x];
    Head[x] = t;


void Tree() 
    t = 0;
    memset(Head, 0, sizeof(Head));
    for (int i = 1; i < n; i++) 
        int x, y, z;
        scanf("%d %d %d", &x, &y, &z);
        add(x, y, z);
        add(y, x, z);
    
    memset(w, 0, sizeof(w));
    Ans = 0;
    work(n, 1);
    cout << Ans << endl;


int main() 
    while (cin >> n >> k && n && k) Tree();
    return 0;

 

以上是关于Tree 点分治的主要内容,如果未能解决你的问题,请参考以下文章

[poj 1741]Tree 点分治

poj1741 Tree 点分治

hdu4812 D Tree 点分治

HDU4871 Shortest-path tree(点分治)

POJ 1741 Tree(点分治)

POJ 1741 Tree ——点分治