/* prufer序列 prufer序列其实就是将带有标号的n个节点(即每个节点不等价)的树用[1,n]的n-2个数唯一表示 即n个点的完全图的生成树与长度为n-2的prufer序列构成一一对应的关系 所以根据prufer序列,我们可以知道,完全图生成树的个数为n^(n-2) */ #include <iostream> using namespace std; typedef long long ll; const int maxn = 5e6+5; int f[maxn],p[maxn],d[maxn]; void solve1(int n) //将无根树转化为prufer序列,因为n这个节点在这一过程中不会被删去 //所以为了方便编码,我们以n为根来构造prufer序列 //a[i]表示当n为根时i的父亲节点 //找到编号最小的叶子节点,将它的父亲节点作为当前的prufer序列的值,然后删去这个节点,直到只剩两个节点 //剩两个节点时,prufer序列的第n-1项一定是n,所以只需要n-2项就可以唯一表示一棵无根树 //如果是有根树,最后两个节点也一定有n,那么第n-1项一定是根,因为这里是无根树,所以我们直接用n做根 { for (int i = 1; i < n; i++) { cin >> f[i]; d[f[i]] ++; } int j = 1; for (int i = 1; i <= n-2; i++) { while( d[j] ) j++; //找编号最小的叶子节点 p[i] = f[j]; d[p[i]] --; while( i < n-2 && d[p[i]] == 0 && p[i] < j ) //删去j点后,当p[i]这个点为叶子时,它比j小,那么下次就一定是选它了 { p[i+1] = f[p[i]]; d[p[i+1]] --; i ++; } j ++; //这个节点用过了 } ll ans = 0; for (int i = 1; i <= n-2; i++) { //cout << p[i] << '\n'; ans ^= (ll)i*p[i]; } cout << ans << '\n'; } void solve2(int n) //在原树中度为x的点,在prufer序列中出现了x-1次 //将prufer序列转化为有根树,遍历prufer序列 //找到编号最小的叶子节点,prufer序列中没有出现的一定为叶子节点 //那么这个叶子节点的父亲就是prufer序列的当前项 { for (int i = 1; i <= n-2; i++) { cin >> p[i]; d[p[i]] ++; } p[n-1] = n; //注意prufer序列是以根为n构造出来的,所以第n-1项一定是n int j = 1; for (int i = 1; i <= n-1; i++) { while( d[j] ) j++; f[j] = p[i]; d[p[i]] --; while( i < n-1 && d[p[i]] == 0 && p[i] < j ) { f[p[i]] = p[i+1]; d[p[i+1]] --; i ++; } j ++; } ll ans = 0; for (int i = 1; i < n; i++) { ans ^= (ll)i*f[i]; } cout << ans; } int main() { ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); int n,m; cin >> n >> m; if( m == 1 ) solve1(n); else solve2(n); return 0; }