题解:P17304 [ICPC 2026 Xi'an I] XOR and LCA
lailai0916 · · 题解
题意简述
一棵树的结点编号为
解题思路
先把树固定以
任取三个结点
令:
代入
固定
其中
原问题已经化成固定根下的无序点对 LCA 异或和
下面求
- 一个点是
x ,另一个点是它的真后代,共operatorname{siz}_x-1 对; - 两点位于不同儿子子树,共
\sum_{i<j}s_is_j 对。
只关心总数的奇偶性。设奇数大小的儿子子树共有
第二类中,只有两个子树大小都为奇数时乘积才是奇数。因此,
实现时先以
结点编号
代码使用度数前缀和建立连续邻接表。所有边只需线性装填,遍历和逆序统计也各执行一次。时间复杂度为
正确性证明
三点在固定根树上的两两 LCA 中,两个较浅值相等,剩余值最深。改根到第三点后,另外两点的 LCA 就是这个最深值。因此,三项异或恒等式成立。
对另外两项做有序化后,异或映射
固定结点
逆序遍历保证处理
参考代码
#include <bits/stdc++.h>
using namespace std;
const int N=(1<<21)+5;
const int M=(1<<22)+5;
int eu[N],ev[N];
int deg[N],st[N],cur[N],e[M];
int fa[N],siz[N],odd[N],q[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin>>T;
while(T--)
{
int p;
cin>>p;
int n=1<<p;
fill(deg,deg+n,0);
for(int i=1;i<n;i++)
{
cin>>eu[i]>>ev[i];
deg[eu[i]]++;
deg[ev[i]]++;
}
st[0]=0;
for(int i=0;i<n;i++)st[i+1]=st[i]+deg[i];
copy(st,st+n,cur);
for(int i=1;i<n;i++)
{
e[cur[eu[i]]++]=ev[i];
e[cur[ev[i]]++]=eu[i];
}
int m=1;
q[0]=0;
fa[0]=-1;
for(int i=0;i<m;i++)
{
int x=q[i];
for(int j=st[x];j<st[x+1];j++)
{
int y=e[j];
if(y==fa[x])continue;
fa[y]=x;
q[m++]=y;
}
}
fill(siz,siz+n,1);
fill(odd,odd+n,0);
int ans=p==1;
for(int i=n-1;i>=0;i--)
{
int x=q[i],k=odd[x];
if((k+k*(k-1)/2)&1)ans^=x;
if(fa[x]!=-1)
{
siz[fa[x]]+=siz[x];
odd[fa[x]]+=siz[x]&1;
}
}
cout<<ans<<'\n';
}
return 0;
}