题解 [Codeforces1156D] 0-1-Tree

题解 [Codeforces1156D] 0-1-Tree

题目来源:Codeforces Educational Round #64

tag:树形 DP,计数


Solution

很容易想到树形 DP,设 f x , 0 / 1 / 2 / 3 f_{x,0/1/2/3} fx,0/1/2/3 表示 x x x 的子树中有多少个点,到 x x x 的路径为全 0 \texttt0 0、全 1 \texttt1 1、先 0 \texttt0 0 1 \texttt1 1,先 1 \texttt1 1 0 \texttt0 0。注意四个状态互相没有重合,且单点不算在路径里。

设当前考虑点 x x x 的答案,每遍历到 x x x 的一棵子树 y y y,就要先计算 y y y 和已经遍历过的 x x x 的子树的答案,再来更新 f x f_x fx。否则会存在类似于 y → x → y y\to x\to y yxy 的路径,不符合题意。所以先统计答案,再考虑状态转移。

统计答案时,先根据 w ( x , y ) w(x,y) w(x,y) 分类。当 w ( x , y ) = 1 w(x,y)=1 w(x,y)=1 时,路径可以分为三类,其中前两类不考虑全 1 \texttt1 1,第三类为全 1 \texttt1 1

  1. y → x y\to x yx y y y 的子树中可以取 f y , 0 + f y , 2 f_{y,0}+f_{y,2} fy,0+fy,2 个点, x x x 已经遍历过的子树中可以取 f x , 1 + 1 f_{x,1}+1 fx,1+1 个点。(因为 x x x 本身也可以取)
  2. x → y x\to y xy x x x 已经遍历过的子树中可以取 f x , 0 + f x , 2 f_{x,0}+f_{x,2} fx,0+fx,2 个点, y y y 的子树中可以取 f y , 1 + 1 f_{y,1}+1 fy,1+1 个点。(因为 y y y 本身也可以取)
  3. 1 \texttt1 1 路径, x x x 已经遍历过的子树中可以取 f x , 1 + 1 f_{x,1}+1 fx,1+1 个点, y y y 的子树中可以取 f y + 1 f_{y+1} fy+1 个点。因为方向有两种,所以答案要再乘上 2 2 2

所以答案累加上 ( f y , 0 + f y , 2 ) ( f x , 1 + 1 ) + ( f x , 0 + f x , 2 ) ( f y , 1 + 1 ) + 2 ( f x , 1 + 1 ) ( f y , 1 + 1 ) (f_{y,0}+f_{y,2})(f_{x,1}+1)+(f_{x,0}+f_{x,2})(f_{y,1}+1)+2(f_{x,1}+1)(f_{y,1}+1) (fy,0+fy,2)(fx,1+1)+(fx,0+fx,2)(fy,1+1)+2(fx,1+1)(fy,1+1)

状态转移式即为:

{ f x , 1 = ∑ y ∈ S o n ( x ) , w ( x , y ) = 1 f y , 1 + 1 f x , 2 = ∑ y ∈ S o n ( x ) , w ( x , y ) = 1 f y , 0 + f y , 2 \begin{cases}f_{x,1}=\sum\limits_{y\in Son(x),w(x,y)=1}f_{y,1}+1\\f_{x,2}=\sum\limits_{y\in Son(x),w(x,y)=1}f_{y,0}+f_{y,2}\end{cases} fx,1=ySon(x),w(x,y)=1fy,1+1fx,2=ySon(x),w(x,y)=1fy,0+fy,2

同理,当 w ( x . y ) = 0 w(x.y)=0 w(x.y)=0 时:

答案累加上 ( f y , 1 + f y , 3 ) ( f x , 0 + 1 ) + ( f x , 1 + f x , 3 ) ( f y , 0 + 1 ) + 2 ( f x , 0 + 1 ) ( f y , 0 + 1 ) (f_{y,1}+f_{y,3})(f_{x,0}+1)+(f_{x,1}+f_{x,3})(f_{y,0}+1)+2(f_{x,0}+1)(f_{y,0}+1) (fy,1+fy,3)(fx,0+1)+(fx,1+fx,3)(fy,0+1)+2(fx,0+1)(fy,0+1)

状态转移:

{ f x , 0 = ∑ y ∈ S o n ( x ) , w ( x , y ) = 0 f y , 0 + 1 f x , 3 = ∑ y ∈ S o n ( x ) , w ( x , y ) = 0 f y , 1 + f y , 3 \begin{cases}f_{x,0}=\sum\limits_{y\in Son(x),w(x,y)=0}f_{y,0}+1\\f_{x,3}=\sum\limits_{y\in Son(x),w(x,y)=0}f_{y,1}+f_{y,3}\end{cases} fx,0=ySon(x),w(x,y)=0fy,0+1fx,3=ySon(x),w(x,y)=0fy,1+fy,3

const int N = 2e5 + 10;
long long ans, f[N][4];
vector<pii> G[N];
int n;

void dfs(int x, int fa){
	for(int i = 0; i < G[x].size(); ++ i){
		int y = G[x][i].first, z = G[x][i].second;
		if(y == fa){
			continue;
		}
		dfs(y, x);
		if(z){
			ans += 2 * (f[y][1] + 1) * (f[x][1] + 1);
			ans += (f[y][0] + f[y][2]) * (f[x][1] + 1);
			ans += (f[x][0] + f[x][2]) * (f[y][1] + 1);
			f[x][1] += f[y][1] + 1;
			f[x][2] += f[y][2] + f[y][0];
		} else {
			ans += 2 * (f[y][0] + 1) * (f[x][0] + 1);
			ans += (f[y][1] + f[y][3]) * (f[x][0] + 1);
			ans += (f[x][1] + f[x][3]) * (f[y][0] + 1);
			f[x][0] += f[y][0] + 1;
			f[x][3] += f[y][3] + f[y][1];
		}
	}
}

void solve(){
	n = rdi;
	for(int i = 1; i < n; ++ i){
		int x = rdi;
		int y = rdi;
		int z = rdi;
		G[x].push_back(make_pair(y, z));
		G[y].push_back(make_pair(x, z));
	}
	dfs(1, 0);
	writen(ans);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值