CodeForces 543d Road Improvement(巧妙地树形dp)

博客探讨了如何使用树形动态规划解决CodeForces上的543d Road Improvement问题。通过将树划分为两部分并从上到下递归计算,实现了巧妙的dp值计算。文章详细介绍了如何计算以任意节点为根的子树dp值,并提供了完整的Java代码实现。
摘要由CSDN通过智能技术生成
//如何求树上任意一点为根的dp值
//将以此点将树划分成两部分,一部分还是原来的子树
//另一部分是此点的父亲往上为子树,这一点的转化很巧妙,一次从上到下的dp即可。
//R[i]记录此点右面子树的乘积,从右到左,其实在最右的时候up[父亲]就已经计算了父亲往上的值了。现在只要记录兄弟即可。

import java.io.*;
import java.util.*;

public class cf {
	FastScanner in;
	final int INF=0x3fffffff;
	final int N=200010;
	final long mod = 1000000007;
	edge[] e;
	int[] head;
	int cnt;
	long[] dp;
	long []L,R;
	long[] ans,up;
	int temp[]=new int[N];

	void addedge(int u,int v){
		e[cnt]=new edge();
		e[cnt].from=u;e[cnt].to=v;
		e[cnt].next=head[u];head[u]=cnt++;
	}
	void DP(int u,int p){
		dp[u]=1;
		for(int i=head[u];i!=-1;i=e[i].next){
			int v=e[i].to;
			if(p==v)continue;
			DP(v,u);
			dp[u]*=(dp[v]+1);
			dp[u]%=mod;
		}
	}
	void DFS(int u,int p){//相当于从上到下再dp一次
		if(p==-1)up[u]=1;L[0]=1;
		int num=0;
		for(int i=head[u],j=0;i!=-1;i=e[i].next,j++){
			int v=e[i].to;
			temp[num++]=v;
			if(p==v){
				L[j+1]=L[j];
				continue;
			}
			L[j+1]=L[j]*(dp[v]+1)%mod;
		}
		R[num-1]=up[u];
		for(int i=num-1;i>0;i--){
			if(temp[i]==p){
				R[i-1]=R[i];
				continue;
			}
			R[i-1]=R[i]*(dp[temp[i]]+1)%mod;
		}
		for(int i=head[u],j=0;i!=-1;i=e[i].next,j++){
			int v=e[i].to;
			if(v==p)continue;
			up[v]=(L[j]*R[j]%mod+1)%mod;
		}
		for(int i=head[u];i!=-1;i=e[i].next){
			int v=e[i].to;
			if(v==p)continue;
			DFS(v,u);
		}
	}
	void input(){
		in = new FastScanner(System.in);
		e=new edge[2*N];
		head=new int[N];
		dp=new long[N];
		L=new long[N];
		R=new long[N];
		ans=new long[N];
		up=new long[N];
		
		Arrays.fill(head, -1);
		int n=in.nextInt();
		cnt=0;
		for(int i=2;i<=n;i++){
			int v=in.nextInt();
			addedge(i,v);
			addedge(v,i);		
		}
		DP(1,-1);
		DFS(1,-1);
		for(int i=1;i<=n;i++)
		System.out.print(up[i]*dp[i]%mod+" ");
	}
		public static void main(String[] args){
		new cf().input();
	}
}
class edge{
	int from,to,next;
}
class FastScanner {
    BufferedReader br;
    StringTokenizer st;

    public FastScanner(File f) {
        try {
            br = new BufferedReader(new FileReader(f));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    public FastScanner(InputStream f) {
        br = new BufferedReader(new InputStreamReader(f));
    }

    String next() {
        while (st == null || !st.hasMoreTokens()) {
            String s = null;
            try {
                s = br.readLine();
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (s == null)
                return null;
            st = new StringTokenizer(s);
        }
        return st.nextToken();
    }

    boolean hasMoreTokens() {
        while (st == null || !st.hasMoreTokens()) {
            String s = null;
            try {
                s = br.readLine();
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (s == null)
                return false;
            st = new StringTokenizer(s);
        }
        return true;
    }

    int nextInt() {
        return Integer.parseInt(next());
    }

    long nextLong() {
        return Long.parseLong(next());
    }

    double nextDouble() {
        return Double.parseDouble(next());
    }
    String nextLine() {
    	
		String str = "";
		try {
			str = br.readLine();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return str;
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值