hdu 5593 ZYB's Tree 树形dp

本文解析了ZYB'sTree问题,介绍了如何通过维护两个DP数组解决节点间距离计算问题。详细阐述了如何利用DFS遍历树结构并计算每个节点周围特定距离内的节点数量。

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

ZYB's Tree

Time Limit: 20 Sec

Memory Limit: 256 MB

题目连接

http://acm.hdu.edu.cn/showproblem.php?pid=5593

Description

ZYB has a tree with N nodes,now he wants you to solve the numbers of nodes distanced no more than K for each node.
the distance between two nodes(x,y) is defined the number of edges on their shortest path in the tree.

To save the time of reading and printing,we use the following way:

For reading:we have two numbers A and B,let fai be the father of node i,fa1=0,fai=(A∗i+B)%(i−1)+1 for i∈[2,N] .

For printing:let ansi be the answer of node i,you only need to print the xor sum of all ansi.

Input

In the first line there is the number of testcases T.

For each teatcase:

In the first line there are four numbers N,K,A,B

1≤T≤5,1≤N≤500000,1≤K≤10,1≤A,B≤1000000

Output

For T lines,each line print the ans.

Please open the stack by yourself.

N≥100000 are only for two tests finally.

Sample Input

1
3 1 1 1

Sample Output

3

HINT

 

题意

 

题解:

我们维护两个dp,dp1[i][j]表示以i为根节点的子树,有多少个点在距离为j的位置

dp2[i][j]表示并不是在子树的,有多少个离他距离为j的点

首先很容易的在树上维护处dp1[i][j]

然后我们再扫一遍用容斥做出dp2就好了

代码:

 

#include<iostream>
#include<stdio.h>
#include<vector>
#include<cstring>
using namespace std;
#define maxn 500050
vector<int> E[maxn];
int dp[maxn][12];
int dp2[maxn][12];

int n,k,A,B;
void dfs(int x)
{
    dp[x][0]=1;
    for(int i=0;i<E[x].size();i++)
    {
        dfs(E[x][i]);
        for(int j=0;j<k;j++)
            dp[x][j+1]+=dp[E[x][i]][j];
    }
}
int main()
{
    int t;scanf("%d",&t);
    for(int cas=1;cas<=t;cas++)
    {
        memset(dp,0,sizeof(dp));
        scanf("%d%d%d%d",&n,&k,&A,&B);
        for(int i=0;i<=n;i++)
            E[i].clear();
        for(int i=2;i<=n;i++)
        {
            int x = i;
            int y = (1LL*A+B*1LL)%(i*1LL-1)+1;
            E[y].push_back(x);
        }
        dfs(1);
        int Ans = 0;
        for(int x=1;x<=n;x++)
        {
            for(int i=0;i<E[x].size();i++)
            {
                int y = E[x][i];
                for(int j=0;j<=k;j++)
                    dp2[y][j]=0;
                dp2[y][1]=dp[x][0];
                for(int j=1;j<k;j++)
                    dp2[y][j+1]=dp[x][j]-dp[y][j-1]+dp2[x][j];
            }
            int now = 0;
            for(int i=0;i<=k;i++)
                now+=dp[x][i]+dp2[x][i];
            Ans^=now;
        }
        printf("%d\n",Ans);
    }

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值