题面:https://www.cnblogs.com/Juve/articles/11390839.html
所有官方正解在我的文件里
A. 虎
算法1:我们发现非关键边与黑色边去掉以后,答案就是将所有度数为奇数的点作为路径的端点,所以记去掉非关键边与黑色边以后度数为奇数的点的个数为s,而一条路径有2个端点,所以答案就是$\frac{s}{2}$。
注意映射
#include<iostream> #include<cstdio> #include<cstring> #define MAXN 1000005 using namespace std; int n,ans=0,du[MAXN],id[MAXN],tot=0; signed main(){ scanf("%d",&n); for(int i=2,x,y,z;i<=n;i++){ scanf("%d%d%d",&x,&y,&z); if(z==0){ if(id[i]) id[x]=id[i]; else if(id[x]) id[i]=id[x]; else id[x]=id[i]=++tot; } if(y==0){ if(!id[i]) id[i]=++tot; if(!id[x]) id[x]=++tot; du[id[i]]++,du[id[x]]++; } } for(int i=2;i<=tot;i++){ if(du[i]&1) ans++; } printf("%d\n",(ans+1)/2); return 0; }
算法2:不妨设0号点为根,那么将i到j的路径取反等价于将0到i和0到j的路径取反,因此只要求出最少需要将多少条到根的路径取反,然后除以二上取整就是答案。用f[i]表示i的子树中所有边(包括 i 连向父亲的边)满足条件时的最少取反路径数,只要先对i的所有儿子的f值求和,然后判断i连向父亲的边是否满足条件,如果不满足再+1即可。