-
贪心
-
对于一个节点来说,显然是对着的可以一条线连下来。所以偶数个的就正好是\(\frac{son}{2}\).
然后对于奇数个的,那就是让偶数个先配上,剩下的一个向上传,这个是不影响父节点的。
最后就是连边的时候,对于已经染成黑色的就不必再建边了。因为动一个已经黑色的不会更优。
对于最后颜色没有要求的,这条边就没什么用处,但是需要它来连接其他边以达到更优解,所以用一种并查集的思想把这条边缩起来,让它的儿子和它的父亲相连即可。
if(!y&&z)f[i]=to[x];
if(!z)to[i]=to[x];
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=1e6+1;
int n;
int f[maxn],to[maxn];
bool vis[maxn];
int ANS=0;
int head[maxn],len=0;
struct E{int to,next,w;}e[maxn<<1];
void A(int x,int y){e[++len].to=y;e[len].next=head[x];head[x]=len;}
int Find(int x){return f[x]==x?x:f[x]=Find(f[x]);}
void Dfs(int u){
vis[u]=1;
int cnt=0;
for(int i=head[u];i;i=e[i].next){
int v=e[i].to;
cnt++;
//printf("%d %d %d\n",u,v,cnt);
Dfs(v);
}//printf("OvO %d %d\n",u,cnt);
if(cnt&1){
if(f[u])ANS+=(cnt-1)/2;
else ANS+=(cnt+1)/2;
}
else {
ANS+=cnt/2;
}
}
int main(){
freopen("tiger.in","r",stdin);
freopen("tiger.out","w",stdout);
scanf("%d",&n);
for(int i=1;i<=n;i++)to[i]=i;
for(int i=2;i<=n;i++){
int x,y,z;scanf("%d%d%d",&x,&y,&z);
if(!y&&z)f[i]=to[x];
if(!z)to[i]=to[x];
}//for(int i=1;i<=n;i++)printf("%d fa=%d\n",i,f[i]);
for(int i=1;i<=n;i++){
if(f[i])A(f[i],i);
}for(int i=1;i<=n;i++){
if(!vis[i]){
Dfs(i);
}
}printf("%d\n",ANS);
return 0;
}