Codeforces Round #417:E. FountainsSagheer and Apple Tree(树上博弈)

 

Codeforces Round #417:E. FountainsSagheer and Apple Tree(树上博弈)

标签: codeforces
  29人阅读  评论(0)  收藏  举报
  分类:

E. Sagheer and Apple Tree
time limit per test
 2 seconds
memory limit per test
 256 megabytes
input
 standard input
output
 standard output

Sagheer is playing a game with his best friend Soliman. He brought a tree with n nodes numbered from 1 to n and rooted at node 1. The i-th node has ai apples. This tree has a special property: the lengths of all paths from the root to any leaf have the same parity (i.e. all paths have even length or all paths have odd length).

Sagheer and Soliman will take turns to play. Soliman will make the first move. The player who can't make a move loses.

In each move, the current player will pick a single node, take a non-empty subset of apples from it and do one of the following two things:

  1. eat the apples, if the node is a leaf.
  2. move the apples to one of the children, if the node is non-leaf.

Before Soliman comes to start playing, Sagheer will make exactly one change to the tree. He will pick two different nodes u and v and swap the apples of u with the apples of v.

Can you help Sagheer count the number of ways to make the swap (i.e. to choose u and v) after which he will win the game if both players play optimally? (u, v) and (v, u) are considered to be the same pair.

Input

The first line will contain one integer n (2 ≤ n ≤ 105) — the number of nodes in the apple tree.

The second line will contain n integers a1, a2, ..., an (1 ≤ ai ≤ 107) — the number of apples on each node of the tree.

The third line will contain n - 1 integers p2, p3, ..., pn (1 ≤ pi ≤ n) — the parent of each node of the tree. Node i has parent pi (for 2 ≤ i ≤ n). Node 1 is the root of the tree.

It is guaranteed that the input describes a valid tree, and the lengths of all paths from the root to any leaf will have the same parity.

Output

On a single line, print the number of different pairs of nodes (u, v)u ≠ v such that if they start playing after swapping the apples of both nodes, Sagheer will win the game. (u, v) and (v, u) are considered to be the same pair.

Examples
input
3
2 2 3
1 1
output
1
input
3
1 2 3
1 1
output
0
input
8
7 2 2 5 4 3 1 1
1 1 1 4 4 5 6
output
4


题意:

有一颗很奇怪的苹果树,这个苹果树所有叶子节点的深度要不全是奇数,要不全是偶数,并且包括根在内的所有节点上都有若干个苹果,现有两个极其聪明的人又来无聊的游戏了,每个人可以吃掉某个叶子节点上的部分苹果(不能不吃),或者将某个非叶子结点上的部分苹果移向它的孩子(当然也不能不移),吃掉树上最后一个苹果的人获胜,问先手是否必胜?不,不是问这个,因为后手可以作弊,他可以交换任意两个节点的苹果数量,问有多少种不同的作弊(交换)方式可以使得后手必胜(不能不交换)?


树上尼姆:

不如考虑什么时候先手必胜,在尼姆博弈中,将所有的苹果个数依次异或,如果最后答案为0就先手必败,否则必胜,那么树上的呢?其实一样,不妨把节点按照深度分成两种:①想要移动到任意叶子结点都需要偶数步数(深度和最深的叶子结点深度奇偶性相同);②想要移动到任意叶子结点都需要奇数步数


对于①,玩家只要移动x个苹果到它孩子节点上,那么这x个苹果就一定会变成状态②之下

对于②玩家只要移动x个苹果到它孩子节点上,那么这x个苹果就一定会变成状态①之下


而孩子结点属于状态①,所以当前玩家只要移动状态②下的x个苹果,那么另一个玩家只要照搬你的移动,将这x个苹果再次移动到当前的孩子,就又变成状态②了,若当前已经到叶子节点无法移动了,另一个玩家就可以直接将这x个苹果吃掉(你就GG,这几个苹果就和没有一样!)


这样就很明显了,先手对于状态②下的苹果,无论怎么移动,最后一定都会被聪明的后手玩家用上述方法吃掉,所以状态②的苹果毫无意义,那么状态①的呢,只要移动一部就会变得状态②从而毫无意义(和没有一样),那这不就转化成了裸的尼姆博弈了么?


结论:只要将所有状态①下的苹果数量异或,最后结果ans若为0则先手必败,否则必胜!


那么怎么解决这道题,其实已经好办了,先判断一波先手必胜还必败。

如果已经必败了,那么后手作弊交换节点时就要尽量避免改变战局,要知道a^b==b^a,异或是满足交换律的,所以B可以将所以状态①中任意两个节点互换,或者将状态②中任意两个节点互换,或者将分别属于状态①和状态②中但数量相同的两堆互换,三种情况个数加在一起即是答案。


如果先手必胜,那么后手的交换一定要改变战局,这个时候必须将状态①中的某个节点和状态②中的某个节点互换,那么怎么换呢?亦或性质a^b^b==a,假设当前异或结果是ans,那么只要遍历一遍状态①中的所有节点,对于当前节点的苹果个数temp,在状态②中找到苹果个数为ans^temp的节点,交换即可!最后统计一遍个数便是答案


[cpp]  view plain  copy
  1. // http://codeforces.com/contest/812/problem/E  
  2. #include<stdio.h>  
  3. #include<algorithm>  
  4. #include<math.h>  
  5. #include<stdlib.h>  
  6. #include<map>  
  7. #include<vector>  
  8. using namespace std;  
  9. #define LL long long  
  10. vector<LL> G[200005];  
  11. map<LL, LL> p, q;  
  12. LL a[200005], dep[200005], maxdep, jl[200005];  
  13. void Sech(LL u, LL p, LL k)  
  14. {  
  15.     LL i, v;  
  16.     dep[u] = k;  
  17.     maxdep = max(maxdep, k);  
  18.     for(i=0;i<G[u].size();i++)  
  19.     {  
  20.         v = G[u][i];  
  21.         if(v==p)  
  22.             continue;  
  23.         Sech(v, u, k+1);  
  24.     }  
  25. }  
  26. int main(void)  
  27. {  
  28.     LL n, i, v, ans, sp, sq, temp, lala;  
  29.     scanf("%I64d", &n);  
  30.     for(i=1;i<=n;i++)  
  31.         scanf("%I64d", &a[i]), jl[i] = a[i];  
  32.     sort(jl+1, jl+n+1);  
  33.     lala = unique(jl+1, jl+n+1)-(jl+1);  
  34.     for(i=2;i<=n;i++)  
  35.     {  
  36.         scanf("%I64d", &v);  
  37.         G[i].push_back(v);  
  38.         G[v].push_back(i);  
  39.     }  
  40.     maxdep = 1;  
  41.     Sech(1, -1, 1);  
  42.     ans = sp = sq = 0;  
  43.     for(i=1;i<=n;i++)  
  44.     {  
  45.         if(maxdep%2==dep[i]%2)  
  46.             p[a[i]]++, ans ^= a[i], sp++;  
  47.         else  
  48.             q[a[i]]++, sq++;  
  49.     }  
  50.     if(ans==0)  
  51.     {  
  52.         ans = sp*(sp-1)/2+sq*(sq-1)/2;  
  53.         for(i=1;i<=lala;i++)  
  54.             ans += p[jl[i]]*q[jl[i]];  
  55.         printf("%I64d\n", ans);  
  56.     }  
  57.     else  
  58.     {  
  59.         temp = ans;  
  60.         ans = 0;  
  61.         for(i=1;i<=n;i++)  
  62.         {  
  63.             if(maxdep%2==dep[i]%2)  
  64.                 ans += q[temp^a[i]];  
  65.         }  
  66.         printf("%I64d\n", ans);  
  67.     }  
  68.     return 0;  
  69. }  
#include<bits/stdc++.h>//博主自己写的垃圾代码
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
int a[maxn],dep[maxn],du[maxn],p[maxn];
map<ll,ll> cnt2;
vector<int> g;
int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
	cin>>a[i];
	for(int i=2;i<=n;i++)
	{
	   cin>>p[i];
	   du[p[i]]++;
    }
    for(int i=1;i<=n;i++)
    {
    	if(du[i]==0)
    	g.push_back(i);
    }
    for(int i=0;i<g.size();i++)
    {
    	dep[g[i]]=0;
    	for(int j=g[i];j!=1;j=p[j])
    	{
    		dep[p[j]]=max(dep[j]+1,dep[p[j]]);
    	}
    }
    ll ans=0,ans1=0,ans2=0;
    for(int i=1;i<=n;i++)
    {
    	if(dep[i]%2==0)
    	{
    		ans=ans^a[i];
    		ans1++;
    	}
    	else cnt2[a[i]]++;
    }
    ll t =0;
    if(ans==0)
    {
    	for(int i=1;i<=n;i++)
    	{
    		if(dep[i]%2==0)
    		{
    			t=t+cnt2[a[i]];
    		}
    	}
    	ans2=n-ans1;
    	cout<<ans1*(ans1-1)/2+ans2*(ans2-1)/2+t<<endl;
    }
    else
    {
    	for(int i=1;i<=n;i++)
		{
			if(dep[i]%2==0)
			{
				t=t+cnt2[ans^a[i]];
			}
		} 
		cout<<t<<endl;
    }
}


E. Sagheer and Apple Tree
time limit per test
 2 seconds
memory limit per test
 256 megabytes
input
 standard input
output
 standard output

Sagheer is playing a game with his best friend Soliman. He brought a tree with n nodes numbered from 1 to n and rooted at node 1. The i-th node has ai apples. This tree has a special property: the lengths of all paths from the root to any leaf have the same parity (i.e. all paths have even length or all paths have odd length).

Sagheer and Soliman will take turns to play. Soliman will make the first move. The player who can't make a move loses.

In each move, the current player will pick a single node, take a non-empty subset of apples from it and do one of the following two things:

  1. eat the apples, if the node is a leaf.
  2. move the apples to one of the children, if the node is non-leaf.

Before Soliman comes to start playing, Sagheer will make exactly one change to the tree. He will pick two different nodes u and v and swap the apples of u with the apples of v.

Can you help Sagheer count the number of ways to make the swap (i.e. to choose u and v) after which he will win the game if both players play optimally? (u, v) and (v, u) are considered to be the same pair.

Input

The first line will contain one integer n (2 ≤ n ≤ 105) — the number of nodes in the apple tree.

The second line will contain n integers a1, a2, ..., an (1 ≤ ai ≤ 107) — the number of apples on each node of the tree.

The third line will contain n - 1 integers p2, p3, ..., pn (1 ≤ pi ≤ n) — the parent of each node of the tree. Node i has parent pi (for 2 ≤ i ≤ n). Node 1 is the root of the tree.

It is guaranteed that the input describes a valid tree, and the lengths of all paths from the root to any leaf will have the same parity.

Output

On a single line, print the number of different pairs of nodes (u, v)u ≠ v such that if they start playing after swapping the apples of both nodes, Sagheer will win the game. (u, v) and (v, u) are considered to be the same pair.

Examples
input
3
2 2 3
1 1
output
1
input
3
1 2 3
1 1
output
0
input
8
7 2 2 5 4 3 1 1
1 1 1 4 4 5 6
output
4


题意:

有一颗很奇怪的苹果树,这个苹果树所有叶子节点的深度要不全是奇数,要不全是偶数,并且包括根在内的所有节点上都有若干个苹果,现有两个极其聪明的人又来无聊的游戏了,每个人可以吃掉某个叶子节点上的部分苹果(不能不吃),或者将某个非叶子结点上的部分苹果移向它的孩子(当然也不能不移),吃掉树上最后一个苹果的人获胜,问先手是否必胜?不,不是问这个,因为后手可以作弊,他可以交换任意两个节点的苹果数量,问有多少种不同的作弊(交换)方式可以使得后手必胜(不能不交换)?


树上尼姆:

不如考虑什么时候先手必胜,在尼姆博弈中,将所有的苹果个数依次异或,如果最后答案为0就先手必败,否则必胜,那么树上的呢?其实一样,不妨把节点按照深度分成两种:①想要移动到任意叶子结点都需要偶数步数(深度和最深的叶子结点深度奇偶性相同);②想要移动到任意叶子结点都需要奇数步数


对于①,玩家只要移动x个苹果到它孩子节点上,那么这x个苹果就一定会变成状态②之下

对于②玩家只要移动x个苹果到它孩子节点上,那么这x个苹果就一定会变成状态①之下


而孩子结点属于状态①,所以当前玩家只要移动状态②下的x个苹果,那么另一个玩家只要照搬你的移动,将这x个苹果再次移动到当前的孩子,就又变成状态②了,若当前已经到叶子节点无法移动了,另一个玩家就可以直接将这x个苹果吃掉(你就GG,这几个苹果就和没有一样!)


这样就很明显了,先手对于状态②下的苹果,无论怎么移动,最后一定都会被聪明的后手玩家用上述方法吃掉,所以状态②的苹果毫无意义,那么状态①的呢,只要移动一部就会变得状态②从而毫无意义(和没有一样),那这不就转化成了裸的尼姆博弈了么?


结论:只要将所有状态①下的苹果数量异或,最后结果ans若为0则先手必败,否则必胜!


那么怎么解决这道题,其实已经好办了,先判断一波先手必胜还必败。

如果已经必败了,那么后手作弊交换节点时就要尽量避免改变战局,要知道a^b==b^a,异或是满足交换律的,所以B可以将所以状态①中任意两个节点互换,或者将状态②中任意两个节点互换,或者将分别属于状态①和状态②中但数量相同的两堆互换,三种情况个数加在一起即是答案。


如果先手必胜,那么后手的交换一定要改变战局,这个时候必须将状态①中的某个节点和状态②中的某个节点互换,那么怎么换呢?亦或性质a^b^b==a,假设当前异或结果是ans,那么只要遍历一遍状态①中的所有节点,对于当前节点的苹果个数temp,在状态②中找到苹果个数为ans^temp的节点,交换即可!最后统计一遍个数便是答案


[cpp]  view plain  copy
  1. // http://codeforces.com/contest/812/problem/E  
  2. #include<stdio.h>  
  3. #include<algorithm>  
  4. #include<math.h>  
  5. #include<stdlib.h>  
  6. #include<map>  
  7. #include<vector>  
  8. using namespace std;  
  9. #define LL long long  
  10. vector<LL> G[200005];  
  11. map<LL, LL> p, q;  
  12. LL a[200005], dep[200005], maxdep, jl[200005];  
  13. void Sech(LL u, LL p, LL k)  
  14. {  
  15.     LL i, v;  
  16.     dep[u] = k;  
  17.     maxdep = max(maxdep, k);  
  18.     for(i=0;i<G[u].size();i++)  
  19.     {  
  20.         v = G[u][i];  
  21.         if(v==p)  
  22.             continue;  
  23.         Sech(v, u, k+1);  
  24.     }  
  25. }  
  26. int main(void)  
  27. {  
  28.     LL n, i, v, ans, sp, sq, temp, lala;  
  29.     scanf("%I64d", &n);  
  30.     for(i=1;i<=n;i++)  
  31.         scanf("%I64d", &a[i]), jl[i] = a[i];  
  32.     sort(jl+1, jl+n+1);  
  33.     lala = unique(jl+1, jl+n+1)-(jl+1);  
  34.     for(i=2;i<=n;i++)  
  35.     {  
  36.         scanf("%I64d", &v);  
  37.         G[i].push_back(v);  
  38.         G[v].push_back(i);  
  39.     }  
  40.     maxdep = 1;  
  41.     Sech(1, -1, 1);  
  42.     ans = sp = sq = 0;  
  43.     for(i=1;i<=n;i++)  
  44.     {  
  45.         if(maxdep%2==dep[i]%2)  
  46.             p[a[i]]++, ans ^= a[i], sp++;  
  47.         else  
  48.             q[a[i]]++, sq++;  
  49.     }  
  50.     if(ans==0)  
  51.     {  
  52.         ans = sp*(sp-1)/2+sq*(sq-1)/2;  
  53.         for(i=1;i<=lala;i++)  
  54.             ans += p[jl[i]]*q[jl[i]];  
  55.         printf("%I64d\n", ans);  
  56.     }  
  57.     else  
  58.     {  
  59.         temp = ans;  
  60.         ans = 0;  
  61.         for(i=1;i<=n;i++)  
  62.         {  
  63.             if(maxdep%2==dep[i]%2)  
  64.                 ans += q[temp^a[i]];  
  65.         }  
  66.         printf("%I64d\n", ans);  
  67.     }  
  68.     return 0;  
  69. }  
#include<bits/stdc++.h>//博主自己写的垃圾代码
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
int a[maxn],dep[maxn],du[maxn],p[maxn];
map<ll,ll> cnt2;
vector<int> g;
int main()
{
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
	cin>>a[i];
	for(int i=2;i<=n;i++)
	{
	   cin>>p[i];
	   du[p[i]]++;
    }
    for(int i=1;i<=n;i++)
    {
    	if(du[i]==0)
    	g.push_back(i);
    }
    for(int i=0;i<g.size();i++)
    {
    	dep[g[i]]=0;
    	for(int j=g[i];j!=1;j=p[j])
    	{
    		dep[p[j]]=max(dep[j]+1,dep[p[j]]);
    	}
    }
    ll ans=0,ans1=0,ans2=0;
    for(int i=1;i<=n;i++)
    {
    	if(dep[i]%2==0)
    	{
    		ans=ans^a[i];
    		ans1++;
    	}
    	else cnt2[a[i]]++;
    }
    ll t =0;
    if(ans==0)
    {
    	for(int i=1;i<=n;i++)
    	{
    		if(dep[i]%2==0)
    		{
    			t=t+cnt2[a[i]];
    		}
    	}
    	ans2=n-ans1;
    	cout<<ans1*(ans1-1)/2+ans2*(ans2-1)/2+t<<endl;
    }
    else
    {
    	for(int i=1;i<=n;i++)
		{
			if(dep[i]%2==0)
			{
				t=t+cnt2[ans^a[i]];
			}
		} 
		cout<<t<<endl;
    }
}


猜你喜欢

转载自blog.csdn.net/silence401/article/details/72845810