https://codeforces.ml/contest/1339/problem/D
给定一个n个顶点的未加权的树,现在你要给每条边分配一个正权重,满足条件:树中每两个不同叶子节点之间的简单路径所有边权按位XOR值为0。
可以放很大(无限大)的数,例如:10(1010),,,
可以确保此类分配在给定约束条件下存在。
定义 f 为叶子节点之间的简单路径上不同边权的数量。
求 f 的最小值和最大值。
例如:
例1.
第一棵树叶子节点1 -> 6之间不同的边权数量为1 (1),所有f=1。
第二棵树叶子节点1 -> 6之间不同的边权数量为4 (1,2,4,7),所有f=4。
f 最小值为1,最大值为4.
例2.
f 最小值最大值都为3.
思路:首先思考最小值,偶数个相同的数异或为0,那么当俩叶子节点之间的边数为偶数时边权都相同就可以了,所以 f最小值为1;当边数出现奇数时,三个相同的数异或值肯定不为0,两个相同的数和一个不同的数异或也肯定不为0,那么就至少要三个不同的数异或,比如边数为5:那么就两个相同的数异或为0,三个不同的数来异或,使异或值为0,如:1^1^1^2^3.所以当边数为奇数时f最小值为3(不可能出现边数为1)。
思考最大值:边数为2的话,这俩数肯定相等,边数不为2的情况,f 就等于边数(我也不知道为什么,猜猜猜,虽然树可能会长的很复杂很奇葩,但应该总能找到那么几个数异或等于0???题目特别说了权重可以非常大,hhhhhh,,,如果有大佬能证明的话,求告知)。
总结:最小值只需要判断叶子节点之间的边数是否有奇数条就可以了,全偶数为1,有奇数为3;
最大值只需找出边数为2的叶子节点,然后减去,先把 f 设为总边数(n-1),同一个节点连的叶子节点的数量为sum,那么 f=f-(sum-1)(sum≥2).
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> using namespace std; const int MAXN=4e5+5; const int mod=1e9+7; typedef long long ll; //typedef __int128 LL; const int inf=0x3f3f3f3f; const long long INF=0x3f3f3f3f3f3f3f3f; vector<int>g[MAXN]; int vis[MAXN]; int len=0;//树的深度,只要顶点到叶子的距离有为奇数的,那么俩叶子节点的边数肯定有为奇数的,同样,如果全为偶数,肯定不存在边数为奇数,就不用计算每两个叶子节点的距离了 int ansmax,ansmin=1; void dfs(int u) { int sum=0;//同一个节点的叶子节点个数 for(int i=0;i<g[u].size();i++) { int v=g[u][i]; if(vis[v]==1)continue; len++; vis[v]=1; if(g[v].size()==1) { sum++; if(len%2&&len>=3)ansmin=3; } dfs(v); len--; } if(sum>=2||len==1) { if(len==1)ansmax=ansmax-sum; else ansmax=ansmax-sum+1; } } int main() { int n; scanf("%d",&n); int u,v; for(int i=1;i<=n-1;i++) { v,u; scanf("%d%d",&v,&u); g[v].push_back(u); g[u].push_back(v); } for(int i=1;i<=n;i++) { if(g[i].size()==1) { u=i;//以叶子节点作为顶点 break; } } ansmax=n-1; vis[u]=1; dfs(u); printf("%d %d\n",ansmin,ansmax); return 0; }