1. 程式人生 > 其它 >BalticOI2021 The Xana coup(切換)

BalticOI2021 The Xana coup(切換)

The Xana coup(切換)BalticOI2021 loj3563

非常顯然,這題一眼望過去就知道是樹形dp,也不難想到令\(dp[x][i][j](i=0/1,j=0/1)\)表示以x為根的子樹(除了x)都變成了0,x為i(對於當前要更新的x,i是沒更新的,對於已經更新過的,i是更新過的),若j為0,則沒有點x,若j為1,則點了一下x。(這裡點了x指,對x進行切換操作)

void dfs(int x,int fa)
{
	dp[x][a[x]^1][0]=dp[x][a[x]^1][1]=inf;
	for(int i=head[x];i;i=edge[i].nxt)
	{
		int y=edge[i].to;
		if(y==fa)
			continue;
		dfs(y,x);
		int a=min(dp[x][0][0]+dp[y][0][0],min(dp[x][1][0]+dp[y][0][1],inf));
		int b=min(dp[x][1][0]+dp[y][0][0],min(dp[x][0][0]+dp[y][0][1],inf));
		int c=min(dp[x][0][1]+dp[y][1][0],min(dp[x][1][1]+dp[y][1][1],inf));
		int d=min(dp[x][1][1]+dp[y][1][0],min(dp[x][0][1]+dp[y][1][1],inf));
		dp[x][0][0]=a;
		dp[x][1][0]=b;
		dp[x][0][1]=c;
		dp[x][1][1]=d;
	}
	int a=min(dp[x][0][1]+1,inf);
	int b=min(dp[x][1][1]+1,inf);
	dp[x][1][1]=a;dp[x][0][1]=b;
}

顯然答案就是 \(min(dp[1][0][0],dp[1][0][1])\)

不得不說 這個樹形dp轉移的時候特別妙妙。為了防止更新答案後又要用更新前的答案,可以先記錄答案,放到所有答案更新完後再更新

反思:這種結論一看就對的題 應該通過小樣例調錯