Codeforces Round #633 (Div. 2)D Edge Weight Assignment(构造、树的权值异或)

时间:2022-07-26
本文章向大家介绍Codeforces Round #633 (Div. 2)D Edge Weight Assignment(构造、树的权值异或),主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

Edge Weight Assignment

time limit per test

1 second

memory limit per test

256 megabytes

input

standard input

output

standard output

You have unweighted tree of nn vertices. You have to assign a positive weight to each edge so that the following condition would hold:

  • For every two different leaves v1v1 and v2v2 of this tree, bitwise XOR of weights of all edges on the simple path between v1v1 and v2v2 has to be equal to 00.

Note that you can put very large positive integers (like 10(1010)10(1010)).

It's guaranteed that such assignment always exists under given constraints. Now let's define ff as the number of distinct weights in assignment.

In this example, assignment is valid, because bitwise XOR of all edge weights between every pair of leaves is 00. ff value is 22 here, because there are 22 distinct edge weights(44 and 55).

In this example, assignment is invalid, because bitwise XOR of all edge weights between vertex 11 and vertex 66 (3,4,5,43,4,5,4) is not 00.

What are the minimum and the maximum possible values of ff for the given tree? Find and print both.

Input

The first line contains integer nn (3≤n≤1053≤n≤105) — the number of vertices in given tree.

The ii-th of the next n−1n−1 lines contains two integers aiai and bibi (1≤ai<bi≤n1≤ai<bi≤n) — it means there is an edge between aiai and bibi. It is guaranteed that given graph forms tree of nn vertices.

Output

Print two integers — the minimum and maximum possible value of ff can be made from valid assignment of given tree. Note that it's always possible to make an assignment under given constraints.

Examples

input

6
1 3
2 3
3 4
4 5
5 6

output

1 4

input

6
1 3
2 3
3 4
4 5
4 6

output

3 3

input

7
1 2
2 7
3 4
4 7
5 6
6 7

output

1 6

Note

In the first example, possible assignments for each minimum and maximum are described in picture below. Of course, there are multiple possible assignments for each minimum and maximum.

In the second example, possible assignments for each minimum and maximum are described in picture below. The ff value of valid assignment of this tree is always 33.

In the third example, possible assignments for each minimum and maximum are described in picture below. Of course, there are multiple possible assignments for each minimum and maximum.

思路:最大值和最小值是两个不同问题,我们分开思考:

最小值:

如果任意两两叶子结点不存在奇数长度简单路径,那么所有路径上随便填一个值,就可以保证两两异或等零了

否则的话,两个数肯定不行,因为最后会剩下一条新的路径,至少要三个数,按照a,b,a,b, c.......的顺序填

其中c=a^b

关于叶子结点之间的长度问题,随便找个根dfs一下就好,然后记录一下各个叶子结点到根的深度,只要存在奇数和偶数长度,那么任意两两叶子结点就存在奇数长度简单路径,否则就没有

最大值:

可以如下构造:

我们设想如果树是一条长链那么答案就是n-1,但当它不是长链,比如多了一个分支,那么这条最长链还是可以保证填的数都不相同,然后新增出来的分支上填的数就等于某些数的异或和(这个和一定是新的),可能有点难理解,但是想象一下应该还好

接着我们就会发现如果某两个叶子结点连边有公共结点,那么一定是要相同的参考第三个例子的左侧的1、2、3结点,1与3连权值1,2与3连权值1,必须要保证相同,那么我们就很容易想出来,只要x个叶子结点有唯一公共结点,就必须答案减x-1(初始值是n-1,因为有n-1条边)

ok,上代码,希望你懂~

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define rg register ll
#define inf 2147483647
#define lb(x) (x&(-x))
ll sz[200005],n;
template <typename T> inline void read(T& x)
{
    x=0;char ch=getchar();ll f=1;
    while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
    while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}x*=f;
}
inline ll query(ll x){ll res=0;while(x){res+=sz[x];x-=lb(x);}return res;}
inline void add(ll x,ll val){while(x<=n){sz[x]+=val;x+=lb(x);}}//第x个加上val
vector<ll>v[100005],check;
ll d[100005],cntt[100005],depth[100005],vis[100005],ou,ji;
inline void dfs(int x,int h,int fa)
{
	depth[x]=h;
	vis[x]=1;
	for(int i=0;i<v[x].size();i++)
	{
		int k=v[x][i];
		if(!vis[k])
		dfs(k,h+1,x);
		
	}
}
int main() 
{
	cin>>n;
	ll ans1,ans2=n-1;
	for(int i=1;i<n;i++)
	{
		ll a,b;
		cin>>a>>b;
		v[a].push_back(b),v[b].push_back(a);
		d[a]++,d[b]++;
	}
	depth[1]=0;
	dfs(1,0,-1);
	ll cnt=0;
	for(int i=1;i<=n;i++)
	{
		
		if(d[i]==1)
		{
			if(depth[i]%2)ji++;
			else ou++;
			cnt++;
			cntt[v[i][0]]++;
		}
	}
	for(int i=1;i<=n;i++)
	{
		if(cntt[i]>=2)ans2-=cntt[i]-1;
	}
	if(ji&&ou)ans1=3;
	else ans1=1;
	cout<<ans1<<" "<<ans2<<endl;
    return 0;
    
}