题解:P14755 西安之泪
题解:P14755 西安之泪
题目大意
给定一棵
- 指定根节点
r 和操作节点u 。 - 在以
r 为根的树中,将u 子树内的所有节点权值异或上u 。
要求构造操作序列,使得最终每个节点
思路
瞪眼法
- 性质:每次操作实际上是以某个节点
r 为根,对节点u 的子树进行集体异或。但要注意,不同的根选择会导致同一个节点u 的子树包含的节点不同。 - 目标转换:最终每个节点
i 需要被异或上i 一次(因为0 \oplus i = i ),且不能受到其他节点的干扰。 - 思路:对于每个节点
u ,我们构造一组操作,使得这组操作的效果是:- 节点
u 被异或上u 一次 - 其他所有节点不被这个
u 的操作影响构造方法
对于每个节点
u ,设其度数为k (邻居个数):
- 节点
- 如果
k 是奇数:- 对
u 的每个邻居v ,进行一次操作(r = v, u = u) 。
- 对
- 如果
k 是偶数:- 先进行一次操作
(r = u, u = u) 。 - 再对
u 的每个邻居v ,进行一次操作(r = v, u = u) 。正确性证明
考虑任意节点
u 的构造:
- 先进行一次操作
- 对
u 本身的影响:- 当
k 为奇数时,u 会出现在每个邻居为根的u 子树中,总共k 次(奇数次)异或u ,效果等价于异或一次。 - 当
k 为偶数时,先以u 为根(包含u 自己),再以每个邻居为根,共k+1 次(奇数次),效果等价于异或一次。
- 当
- 对其他节点
x 的影响:- 设
x \neq u ,v_0 是u 到x 路径上u 的第一个邻居。 - 当以
v_0 为根时,x 不在u 的子树中。 - 当以
u 的其他邻居为根时,x 在u 的子树中 - 因此
x 被异或的次数为: -
- 设
- 总体效果:
- 每个节点
u 的构造只让u 自己被异或上u 。 - 不同节点的操作相互独立,最终每个节点
i 的权值为i 。
- 每个节点
代码实现
#include<bits/stdc++.h>
using namespace std;
int main(){
int T;
cin>>T;
while(T--){
int n;
cin>>n;
vector<vector<int>> adj(n+1);
for(int i=0,u,v;i<n-1;++i)
cin>>u>>v,adj[u].push_back(v),adj[v].push_back(u);
vector<pair<int,int>> ops;
for(int u=1;u<=n;++u){
int k=adj[u].size();
if(k%2)for(int v:adj[u])ops.emplace_back(v,u);
else{
ops.emplace_back(u,u);
for(int v:adj[u])ops.emplace_back(v,u);
}
}
cout<<ops.size()<<'\n';
for(auto[r,u]:ops)cout<<r<<' '<<u<<'\n';
}
return 0;
}
时间复杂度每次