标签:tween put 判断 finally output using 需要 == oal
Ashish has a tree consisting of nn nodes numbered 11 to nn rooted at node 11 . The ii -th node in the tree has a cost aiai , and binary digit bibi is written in it. He wants to have binary digit cici written in the ii -th node in the end.
To achieve this, he can perform the following operation any number of times:
He wants to perform the operations in such a way that every node finally has the digit corresponding to its target.
Help him find the minimum total cost he needs to spend so that after all the operations, every node uu has digit cucu written in it, or determine that it is impossible.
Input
First line contains a single integer nn (1≤n≤2⋅105)(1≤n≤2⋅105) denoting the number of nodes in the tree.
ii -th line of the next nn lines contains 3 space-separated integers aiai , bibi , cici (1≤ai≤109,0≤bi,ci≤1)(1≤ai≤109,0≤bi,ci≤1) — the cost of the ii -th node, its initial digit and its goal digit.
Each of the next n−1n−1 lines contain two integers uu , vv (1≤u,v≤n, u≠v)(1≤u,v≤n, u≠v) , meaning that there is an edge between nodes uu and vv in the tree.
Output
Print the minimum total cost to make every node reach its target digit, and −1−1 if it is impossible.
Examples
Input
Copy
5
1 0 1
20 1 0
300 0 1
4000 0 0
50000 1 0
1 2
2 3
2 4
1 5
Output
Copy
4
Input
Copy
5
10000 0 1
2000 1 0
300 0 1
40 0 0
1 1 0
1 2
2 3
2 4
1 5
Output
Copy
24000
Input
Copy
2
109 0 1
205 0 1
1 2
Output
Copy
-1
我好菜TAT 一开始思路偏到树形多重背包上去了,看到题解才恍然大悟
题意是给一棵树,每个节点i有代价a[i],初始值b[i]和最终值c[i](b[i],c[i]范围是0/1),每次操作可以把某个节点u的子树上的任意k(k任意)个节点的值变成想要的,花费为a[u]*k,问最终所有节点变成最终值的最小花费是多少。
首先注意到不可能的情况,一定是0变1的节点数不等于1变0的节点数,用两个变量统计直接判断即可。
然后思考能变换的情况。考虑当前节点u以及u的所有子树v1,v2…vn(子树不包括u)。对于某一棵子树vi里的需要由1变为0的节点数(记为to0)和需要由0变为1的节点数(记为to1)既可以在vi这棵子树里发生转变,也可以在u为根或者u的父亲节点或者爷爷节点或者爷爷的爷爷节点…乃至最终的根节点里发生转换。因此,我们首先在DFS的过程中把a数组更新,使得a[i]代表i这个节点到根节点的路径上的花费的最小值。这样根节点到任意节点的路径的a序列是一个单调不增的序列了。这样做有什么用呢?显然这样的话我们就能直接先把子树里能成对变换的节点的最少花费预先求出来并累加到答案里,即ans+=a[x]*2*min(to1,to0)。然后可能会剩下需要0变1的节点或者1变0的节点,这部分点直接上传给父亲节点,让父亲节点去凑即可。因为是成对变换,最终给根节点留下的肯定也能配对。最终直接输出ans即可,复杂度O(n)。
#include <bits/stdc++.h> #define N 200005 using namespace std; int a[N],b[N],c[N],head[N],Next[2*N],ver[2*N],tot=0,n; long long ans=0; void add(int x,int y) { ver[++tot]=y,Next[tot]=head[x],head[x]=tot; } struct node { int to0; int to1; }; node dfs(int x,int pre) { bool flag=0; int i; node cnt={0,0}; if(b[x]==0&&c[x]==1) cnt.to1++; else if(b[x]==1&&c[x]==0) cnt.to0++; for(i=head[x];i;i=Next[i]) { int y=ver[i]; if(y==pre) continue; a[y]=min(a[x],a[y]); node temp=dfs(y,x); cnt.to0+=temp.to0;//子树里没法配对的 累加到当前节点需要凑的里面 cnt.to1+=temp.to1; } if(cnt.to0>cnt.to1)//最后上传回去的to0或者to1里一定有一个是0 { ans+=(long long)a[x]*cnt.to1*2;//这部分能直接求出来 cnt.to0-=cnt.to1; cnt.to1=0; } else { ans+=(long long)a[x]*cnt.to0*2;//成对变 得乘以2 cnt.to1-=cnt.to0; cnt.to0=0; } return cnt; } int main() { cin>>n; int i; int cnt1=0,cnt2=0; for(i=1;i<=n;i++) { scanf("%d%d%d",&a[i],&b[i],&c[i]); if(b[i])cnt1++;//判断是否输出-1 if(c[i])cnt2++; } for(i=1;i<=n-1;i++) { int u,v; scanf("%d%d",&u,&v); add(u,v); add(v,u); } if(cnt1!=cnt2) { cout<<-1<<endl; return 0; } ans+=a[1]*dfs(1,0).to0;//最后留给根节点的一定能凑对 cout<<ans<<endl; }
Codeforces Round #646 (Div. 2) E. Tree Shuffling(贪心/树形DP)
标签:tween put 判断 finally output using 需要 == oal
原文地址:https://www.cnblogs.com/lipoicyclic/p/13028271.html