码迷,mamicode.com
首页 > 其他好文 > 详细

[POJ 1741] Tree 点分治

时间:2017-08-04 22:47:10      阅读:240      评论:0      收藏:0      [点我收藏+]

标签:sdi   inline   end   algo   实现   多少   list   git   题意   

题意

  给定 n 个节点的树.

  求有多少对节点 (u, v) , 满足 dist(u, v) <= K .

  n <= 10000.

 

实现

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#include <vector>
using namespace std;
#define F(i, a, b) for (register int i = (a); i <= (b); i++)
inline int rd(void) {
    int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == -) f = -1;
    int x = 0; for (; isdigit(c); c = getchar()) x = x*10+c-0; return x*f;
}

const int N = 10005;

#define fore(it, x) for (register vector<E>::iterator it = g[x].begin(); it != g[x].end(); it++)
int n, K;
struct E { int v, d; inline E(int _v = 0, int _d = 0): v(_v), d(_d) {} }; vector<E> g[N];
inline void Init(int u, int v, int d) { g[u].push_back(E(v, d)), g[v].push_back(E(u, d)); }

int siz[N], num; bool vis[N];
int s[N], top;
int res;

inline int Siz(int x, int par) {
    siz[x] = 1;
    fore(it, x) if (!vis[it->v] && it->v != par)
        siz[x] += Siz(it->v, x);
    return siz[x];
}
inline int Root(int x, int par) {
    fore(it, x) if (!vis[it->v] && it->v != par) {
        if (siz[it->v] > (num >> 1)) return Root(it->v, x);
    }
    return x;
}

inline void List(int x, int par, int Dist) {
    s[++top] = Dist;
    fore(it, x) if (!vis[it->v] && it->v != par)
        List(it->v, x, Dist + it->d);
}
inline int Calc(int x, int par, int Dist, int sign) {
    top = 0, List(x, par, Dist);
    sort(s+1, s+top+1);
    int sum = 0;
    for (int i = top, j = 0; i >= 1; i--) {
        while (j < i && s[i]+s[j+1] <= K) j++;
        if (i == j) j--;
        sum += j;
    }
    return sum * sign;
}

void Solve(int f) {
    num = Siz(f, -1);
    int x = Root(f, -1);
    
    res += Calc(x, -1, 0, +1);
    fore(it, x) if (!vis[it->v])
        res += Calc(it->v, x, it->d, -1);
    
    vis[x] = true;
    fore(it, x) if (!vis[it->v])
        Solve(it->v);
}

int main(void) {
    for (n = rd(), K = rd(); n > 0 || K > 0; n = rd(), K = rd()) {
        F(i, 1, n-1) {
            int u = rd(), v = rd(), d = rd();
            Init(u, v, d);
        }
        
        memset(vis, 0, sizeof vis), res = 0;
        Solve(1);
        printf("%d\n", res);
        
        F(i, 1, n) g[i].clear();
    }
    return 0;
}

 

[POJ 1741] Tree 点分治

标签:sdi   inline   end   algo   实现   多少   list   git   题意   

原文地址:http://www.cnblogs.com/Sdchr/p/7287217.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!