10 分树上 DP 求调
查看原帖
10 分树上 DP 求调
822239
ncwzdlsd楼主2023/2/17 07:53

未用换根思路,容斥解决,求调

#include<bits/stdc++.h>
using namespace std;

const int maxn=100005*2;
int head[maxn],to[maxn],nxt[maxn],cnt,dp[maxn][25][2],m[maxn],k,father[maxn]; 
//f[i][j][0]表示只考虑节点i的子树,与节点i距离小于等于j的节点权值之和(包括当前节点)
//f[i][j][1]表示对于该点父节点,与该点父节点距离小于等于j-1的节点权值之和(忽略当前子节点)(符合条件的)

void add(int x,int y)
{
	to[++cnt]=y;
	nxt[cnt]=head[x];
	head[x]=cnt;
}

void dfs(int x,int fa)
{
	father[x]=fa;
	for(int i=1;i<=k;i++)
		dp[x][i][0]=dp[x][0][0];
	for(int i=head[x];i;i=nxt[i])
    {
        if(to[i]==fa) continue;
        dfs(to[i],x);
		for(int j=1;j<=k;j++)
			dp[x][j][0]+=dp[to[i]][j-1][0];
    }
    for(int i=head[x];i;i=nxt[i])
    {
    	if(to[i]==fa) continue;
    	dp[to[i]][1][1]=dp[x][0][0];
    	for(int j=2;j<=k;j++)
    		dp[to[i]][j][1]=dp[x][j-1][0]-dp[to[i]][j-2][0];
    		// 考虑to[i]的父节点即x,因为有多的点权所以要用到容斥原理处理
    		// 举个栗子,对于一个二叉树(中序遍历)7-4-2-1-3-5-8-9-6,我们要求距离节点2距离为3的点,我们找到2的父亲1,找与1距离为2的点,发现有4 5 6不符合(与子树同层的点)
    		// 这些点的特征就是距离节点2的距离为k-2
    }
}

int main()
{
    int n,u,v;cin>>n>>k;
    for(int i=1;i<n;i++) cin>>u>>v,add(u,v),add(v,u);
    for(int i=1;i<=n;i++) cin>>dp[i][0][0];
    dfs(1,0);
    for(int i=1;i<=n;i++) m[i]=dp[i][k][1];
	for(int i=1;i<=n;i++)
	{
		m[i]=dp[i][k][0];int id=i;
		for(int j=1;j<=n;j++)
		{
			m[i]+=dp[id][k-j+1][1];
			u=father[u];
			if(!u) break;
		}
	}
	for(int i=1;i<=n;i++) cout<<m[i]<<endl;
    return 0;
}
2023/2/17 07:53
加载中...