您的位置:首页 > 其它

poj 1741 树分治

2015-08-19 11:33 323 查看
题意:

  求树上距离不超过k的点对数

解决:

  很经典的树分治

  先不考虑树退化的情况。

  对每个节点u,假设u有x个子节点,v1 v2 v3 .. vx,求出以u为根的子树上,所有不属于同一个v节点的,且距离不大于k的点对数。

  且递归下去就是答案,无重无缺。

  至于如何求上述的点对数量,

  假设A = 以u为根节点的子树上所有的距离不大于k的点对数

    B = 以u为根节点的子树上,同时属于u的某个同一个子节点v的,且距离不大于k的点对数

  则 A - B 即为答案

  

  下面加上,考虑树退化的问题,每次在dfs的时候,找到当前u为根的子树的重心,作为根去处理即可。

  

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>

const int MAXN = 1e4+10;
const int MAXM = MAXN<<2;

struct Edge{
int u, v, w, next;
Edge(int _u, int _v, int _w, int _next)
{
u = _u;
v = _v;
w = _w;
next = _next;
}
Edge(){}
}edge[MAXM];
int tot, head[MAXN];
int n, k;
int siz[MAXN];
int max_sub[MAXN];
int dist[MAXN];
bool vis[MAXN];
int max_siz, root;
std::vector<int> ve;
int res;

void inline addEdge(int u, int v, int w)
{
edge[++tot] = Edge(u, v, w, head[u]);
head[u] = tot;
}

void init()
{
tot = 1;
res = 0;
memset(head, 0, sizeof head);
memset(vis, false, sizeof vis);
}

void getRoot(int u, int fa_node, int root_now)
{
max_sub[u] = std::max(max_sub[u], siz[root_now] - siz[u]);
if (max_siz > max_sub[u]) {
max_siz = max_sub[u];
root = u;
}
for (int i = head[u]; i > 0; i = edge[i].next) {
int v = edge[i].v;
if (v == fa_node || true == vis[v])
continue;
getRoot(v, u, root_now);
}
}

void getSize(int u, int fa_node)
{
siz[u] = 1, max_sub[u] = 0;
for (int i = head[u]; i > 0; i = edge[i].next) {
int v = edge[i].v;
if (v == fa_node || true == vis[v])
continue;
getSize(v, u);
siz[u] += siz[v];
max_sub[u] = std::max(max_sub[u], siz[v]);
}
}

void getDist(int u, int fa_node, int d)
{
ve.push_back(d);
for (int i = head[u]; i > 0; i = edge[i].next) {
int v = edge[i].v, w = edge[i].w;
if (v == fa_node || true == vis[v])
continue;
getDist(v, u, d+w);
}
}

int calc(int u, int d)
{
ve.clear();
getDist(u, -1, d);
std::sort(ve.begin(), ve.end());
int ans = 0;
int l = 0, r = ve.size() - 1;
while (l <= r) {
if (ve[l] + ve[r] <= k) {
ans += (r - l);
++l;
}
else
--r;
}
return ans;
}

void dfs(int u)
{
getSize(u, -1);
max_siz = n;
getRoot(u, -1, u);
res += calc(root, 0);
vis[root] = true;
for (int i = head[root]; i > 0; i = edge[i].next) {
int v = edge[i].v, w = edge[i].w;
if (true == vis[v])
continue;
res -= calc(v, w);
dfs(v);
}
}

int main()
{
while (~scanf("%d%d", &n, &k), (n||k)) {
init();
for (int i = 1, u, v, w; i <= n-1; ++i) {
scanf("%d%d%d", &u, &v, &w);
addEdge(u, v, w);
addEdge(v, u, w);
}
dfs(1);
printf("%d\n", res);
}
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: