buptoj 945:Emiya 树形dp

本文介绍了一种使用树形DP算法解决特定节点距离查询问题的方法。在一个给定的树结构中,通过两次深度优先搜索(DFS),可以高效地计算出离指定节点特定距离的节点数量。首次DFS用于计算子节点距离,而第二次则更新整个树上的距离信息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

时间限制 5000 ms  内存限制 65536 KB

题目描述

There are N Assassin in a town. Each of them hides in a building and there aren't no two paths between any two of Assasin (You could think the buildings form a tree),every building has a number which is from 1 to N. Now Emiya comes to the town. As an Archer ,Emiya could shoot any enimy even though it is far away from him . And Archer wants to know ,how many Assassins are exactly d kilometers away from him if he comes to a building numbered x? You could think every buildings is 1 kilometers away from its neighbors.

输入格式

There are multiple test cases. Please process till EOF. The number of test cases is not exceed 100.

The first line contains two number N and Q,which indicate the number of Assassins(Buildings) and the number of questions Emiya would ask.

Then following N-1 lines ,each line contains two number u and v,indicating there is a road between buildings u and buildings v.

The next Q lines are questions, each line contains two number x and d ,indicating the Building where Emiya comes in and the distance.

( 1N,Q105,d10 )

输出格式

For each questions : ouput how many Assasins are exactly d kilometers away from the Building x.

输入样例

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

输出样例

3
1
3
2
1

题意:给定一棵树,有Q个询问,每次询问是到某一个节点距离为d的节点有多少个。d<=10。

两次深搜,一次搜寻下面到自己距离为d的个数,即以自己为根节点,子节点距离自己距离为d的个数。

第二次搜是要加上上面距离自己距离为d的个数,all[x][d]=down[x][d]+all[fa][d-1]-down[x][d-2]。即上面节点到父节点距离为d-1的到该节点距离就是d了,但是这里面包括了自己的子节点,所以要剪掉到自己距离为d-2的节点。

代码:

/*
USER_ID: test#299792458ms
PROBLEM: 945
SUBMISSION_TIME: 2016-03-21 18:19:18
*/
 
#pragma warning(disable:4996)
#include <iostream>
#include <functional>
#include <algorithm>
#include <cstring>
#include <vector>
#include <string>
#include <cstdio>
#include <cmath>
#include <queue>
#include <stack>
#include <deque>
#include <ctime>
#include <set>
#include <map>
using namespace std;
typedef long long ll;
 
#define INF 0x33ffffff
 
#define eps 1e-6
const ll mod = 1000000007;
const int maxn = 1e5 + 5;
const double PI = acos(-1.0);
 
int n, q, edgen;
int head[maxn], vis[maxn];
int all[maxn][12],down[maxn][12];
 
struct ed
{
    int to;
    int next;
}edge[maxn * 3];
 
void addedge(int st, int to)
{
    edgen++;
    edge[edgen].to = to;
    edge[edgen].next = head[st];
    head[st] = edgen;
}
void init()
{
    edgen = 0;
    memset(all, 0, sizeof(all));
    memset(down, 0, sizeof(down));
    memset(head, -1, sizeof(head));
    for (int i = 0; i <= n; i++)
    {
        down[i][0] = 1;
    }
}
 
void dfs1(int x)
{
    int i, j, k;
    for (i = head[x]; i != -1; i = edge[i].next)
    {
        k = edge[i].to;
        if (vis[k] == 0)
        {
            vis[k] = 1;
            dfs1(k);
            for (j = 1; j <= 10; j++)
            {
                down[x][j] += down[k][j - 1];
            }
        }
    }
}
 
void dfs2(int x, int fa)
{
    int i, j, k;
    for (i = 0; i <= 10; i++)
    {
        all[x][i] = down[x][i];
    }
    if (fa != -1)
    {
        for (i = 1; i <= 10; i++)
        {
            all[x][i] += all[fa][i - 1];
            if (i > 1)all[x][i] -= down[x][i - 2];
        }
    }
    for (i = head[x]; i != -1; i = edge[i].next)
    {
        k = edge[i].to;
        if (vis[k] == 0)
        {
            vis[k] = 1;
            dfs2(k, x);
        }
    }
}
 
void solve()
{
    int i, j, k;
    int u, v;
    for (i = 1; i <= n - 1; i++)
    {
        scanf("%d%d", &u, &v);
        addedge(u, v);
        addedge(v, u);
    }
    memset(vis, 0, sizeof(vis));
    vis[1] = 1;
    dfs1(1);
     
    memset(vis, 0, sizeof(vis));
    vis[1] = 1;
    dfs2(1, -1);
 
    for (i = 1; i <= q; i++)
    {
        scanf("%d%d", &u, &v);
        printf("%d\n", all[u][v]);
    }
}
 
int main()
{
#ifdef wangchong756 
    freopen("i.txt", "r", stdin);
    freopen("o.txt", "w", stdout);
    int time_wangchong756 = clock();
#endif
    while (scanf("%d%d", &n, &q) != EOF)
    {
        init();
        solve();
    }
    //system("pause");
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值