题目链接
题目大意:
给定一棵树,给每条边一个正权值然后使得任何两个叶子之间的路径上的异或和为0。输出边的权值的种类的最大值和最小值。
解题思路:
最小值:
只有1,3两种答案。如果两个叶子之间的距离为奇数,可以都转化为3进行处理,此时必须有三种值,因为如果是两种或一种值,则一样的值异或掉会剩下一个值。如果是长度都为偶数则只需要1种就可以了。
距离只要选取一个叶子作为根节点,然后进行dfs求深度就可以了。因为两个叶子如果到根的距离奇偶性不同,则他们之间距离就为奇数,如果到根的奇偶性相同则两个叶子之间的奇偶性也是一样。
最大值:
可以看出如果每条边权都为
都不相同,则两边绝对不会异或出另一条边的值。所以此时每条边的权值都为
就行了,就有n-1条边,但是如果一个节点有多个直接的儿子叶子节点,则这些边权值必须都相等,因为长度只为2,就必须相同。所以减掉当前节点的是直接儿子也是叶子的数量-1。
对于每一个叶子和父节点之间边权值设置为根到他的父亲路径上的异或和,这样就能保证任何两个叶子节点之间路径上的异或和都是0。(可以画图理解一下)
解题代码
#include<bits/stdc++.h>
using namespace std;
mt19937 rng_32(chrono::steady_clock::now().time_since_epoch().count());
typedef long long ll;
const int maxn=2e5+10;
struct E{
int to,nxt;
}e[maxn];
int sonsz[maxn];
int head[maxn],tot;
void adde(int u,int v)
{
e[++tot]=E{v,head[u]};
head[u]=tot;
}
int d[maxn];
bool odd;
void dfs(int u,int fa,int dep)
{
int c=0;
for (int i=head[u];i;i=e[i].nxt)
{
int to=e[i].to;
if (to==fa)
continue;
c++;
dfs(to,u,dep+1);
}
//奇偶性标记
if (c==0 && (dep&1))
odd=1;
}
int main()
{
int n,t1,t2;
int lea=0;
cin>>n;
for (int i=1;i<n;i++)
{
cin>>t1>>t2;
d[t1]++;
d[t2]++;
adde(t1,t2);
adde(t2,t1);
}
int top=1;
ll ans=n-1;
for (int i=1;i<=n;i++)
{
if (d[i]==1)
{
top=i;
lea++;
//给直接父亲的儿子叶子+1
sonsz[e[head[i]].to]++;
//如果不止一个 就要减掉
if (sonsz[e[head[i]].to]!=1)
ans--;
}
}
dfs(top,top,0);
if (odd)
cout<<3<<" ";
else
cout<<1<<" ";
cout<<ans;
return 0;
}