联赛模拟测试14 A. 虎

题目描述

这题太虎了,所以没有背景。
给你一棵树,边有黑白两种颜色,你每次可以选择两个点,把这两个点之间的唯一简单路径上的所有边颜色取反,某些边要求最终颜色必须是黑色,还有些边没有要求,问最少操作多少次能达到目的

输入格式

第一行一个整数 (n),代表点数
接下来(n-1)行,每行三个数(x,y,z),代表点 (i) 与点 (x) 之间有一条边,若 (y)(0) 代表初始为白色,否则为黑色,若(z)(0)代表不对最终颜色做要求,否则代表要求为黑色。

输出格式

达到目的的最少操作多少次数

样例

样例输入

7
1 0 1
1 1 1
2 0 1
2 0 1
3 1 1
3 0 1

样例输出

3

数据范围与提示

对于 (30\%) 的数据,所有(x)等于(1)

对于另外 (30\%) 的数据,所有边最终都必须为黑色

对于 (100\%) 的数据,(n leq 1000000)

分析

树上的贪心
如果儿子中有偶数个节点不符合条件,直接两两配对
否则将剩下的节点能上传就上传

代码

#include<cmath>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define rg register
inline int read(){
	rg int x=0,fh=1;
	rg char ch=getchar();
	while(ch<'0' || ch>'9'){
		if(ch=='-') fh=-1;
		ch=getchar();
	}
	while(ch>='0' && ch<='9'){
		x=(x<<1)+(x<<3)+(ch^48);
		ch=getchar();
	}
	return x*fh;
}
const int maxn=2e6+5;
int n,h[maxn],tot=1;
struct asd{
	int to,nxt,val;
}b[maxn];
void ad(int aa,int bb,int cc){
	b[tot].to=bb;
	b[tot].nxt=h[aa];
	b[tot].val=cc;
	h[aa]=tot++;
}
int ans;
int dfs(int now,int fa){
	rg int cnt=0;
	for(rg int i=h[now];i!=-1;i=b[i].nxt){
		rg int u=b[i].to;
		if(u==fa) continue;
		rg int haha=dfs(u,now);
		if(b[i].val==1){
			cnt++;
		} else if(haha){
			if(b[i].val==-1) cnt++;
			else ans++;
		}
	}
	ans+=cnt/2;
	if(cnt&1) return 1;
	else return 0;
}
int main(){
	memset(h,-1,sizeof(h));
	n=read();
	rg int aa,bb,cc;
	for(rg int i=2;i<=n;i++){
		aa=read(),bb=read(),cc=read();
		if(cc==0){
			ad(i,aa,-1);
			ad(aa,i,-1);
		} else {
			if(bb==0){
				ad(i,aa,1);
				ad(aa,i,1);
			} else {
				ad(i,aa,0);
				ad(aa,i,0);
			}
		}
	}
	ans+=dfs(1,0);
	printf("%d
",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/liuchanglc/p/13800881.html