Tree Shuffling(树形dp)
Posted 爷灬傲奈我何123
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Tree Shuffling(树形dp)相关的知识,希望对你有一定的参考价值。
link
题意:
给你一棵以1为根的树,和每个点的a,b,c ,a代表操作的花费,b代表当前他的值,c代表目标值,每次你可以选一个点花费k*size两两交换他的子节点,问让所有值变成目标值的花费。
思路:
一开始想到可以从根到u的交换值取min,对于原始和目标值相同的点我们可以不用管,因为早晚还要进行一次交换,证明:
假设有1/1 0/1 1/0,我们操作{1/1,0/1},{0/1,1/0},不如直接操作{0/1,1/0}.
后来就想不到了,题解说可以设dp[u][2]代表遍历到u,0/1还没有处理的个数,然后由于从根到该节点是递减的,那么深度越大的话,我们尽量操作完,因为代价最小,详细操作就是每次维护dp数组,减去0和1的min。如果最终dp[1][0]和dp[1][1]不同那么就是不合法的。
代码:
// Problem: CF1363E Tree Shuffling
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/CF1363E
// Memory Limit: 250 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
//#pragma GCC target("avx")
//#pragma GCC optimize(2)
//#pragma GCC optimize(3)
//#pragma GCC optimize("Ofast")
// created by myq
#include<iostream>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<climits>
#include<cmath>
#include<cctype>
#include<stack>
#include<queue>
#include<list>
#include<vector>
#include<set>
#include<map>
#include<sstream>
#include<unordered_map>
#include<unordered_set>
using namespace std;
typedef long long ll;
#define x first
#define y second
typedef pair<int,int> pii;
const int N = 200010;
const int mod=998244353;
vector<int>v[N];
int dp[N][2];
inline int read()
{
int res=0;
int f=1;
char c=getchar();
while(c>'9' ||c<'0')
{
if(c=='-') f=-1;
c=getchar();
}
while(c>='0'&&c<='9')
{
res=(res<<3)+(res<<1)+c-'0';
}
return res;
}
int a[N],b[N],c[N];
ll res=0;
void dfs(int u,int fa)
{
if(b[u]!=c[u])
{
dp[u][0]+=b[u]==0;
dp[u][1]+=b[u]==1;
}
if(fa) a[u]=min(a[u],a[fa]);
for(auto j:v[u])
{
if(j==fa) continue;
dfs(j,u);
dp[u][0]+=dp[j][0];
dp[u][1]+=dp[j][1];
}
int minv=min(dp[u][0],dp[u][1]);
res+=1ll*minv*2*a[u];
dp[u][0]-=minv;
dp[u][1]-=minv;
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n;
cin>>n;
int cnt1=0;
int cnt2=0;
for(int i=1;i<=n;i++)
{
cin>>a[i]>>b[i]>>c[i];
if(b[i]!=c[i])
{
cnt1+=b[i]==0;
cnt2+=b[i]==1;
}
}
if(cnt1!=cnt2)
{
cout<<-1;
return 0;
}
for(int i=0;i<n-1;i++)
{
int a,b;
cin>>a>>b;
v[a].push_back(b);
v[b].push_back(a);
}
dfs(1,0);
cout<<res<<endl;
return 0;
}
/**
* In every life we have some trouble
* When you worry you make it double
* Don't worry,be happy.
**/
以上是关于Tree Shuffling(树形dp)的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces Round #646 (Div. 2) E. Tree Shuffling(树上dp)