题解:AT_agc052_b [AGC052B] Tree Edges XOR
思路
AT_agc052_b [AGC052B] Tree Edges XOR 题目 Link
文中 \(\oplus\) 表示按位异或。
翻看@Soh_paramEEMS 大神的题解,发现有一个题挺有意思,之前做过但是过了时间有点久,现在来看又有新发现了。
具体地,我在图上(树上)问题 trick提到了点边互化的 trick,这题是一个挺成功的范例。具体来说,我们首先要用惊人的注意力发现一次操作的本质。假设选定边 \((u,v)\),边权是 \(w\),然后规定树上任意两点的距离是它们最短路径上边权的异或和(这是一个弱条件的归约,我们通过距离这一弱条件映射约束更强的问题)。不妨令 \(u\) 到所有点的距离集合为 \(s_u\),那么我们的实质相当于交换了集合 \(s_u,s_v\)。
Proof
何以见得?考虑其对树上节点距离的影响。用边 \((u,v)\) 把这棵树劈开两半,我们试找到 \(a,b\)(与 \(u,v\) 两两互不相等),它们的距离会如何改变?
分类讨论,如果 \(a,b\) 在同一半,由于这两个点中没有 \(u,v\),所以它们的距离不会改变。如果 \(a,b\) 不在同一半,又由于这两个点中没有 \(u,v\),所以它们的距离相当于其中有两条边分别 \(\oplus w\),最终相当于没异或。
接下来讨论 \(u,a\) 和 \(v,a\) 的情况。
如果 \(u,a\) 在同一半那么其距离中必然会恰出现一条边 \(\oplus w\)。如果 \(u,a\) 不在同一半那么又由于规定了 \(a\neq v\),所以也恰会出现一条边 \(\oplus w\)。
对 \(v\) 的讨论是同理的。然后我们就发现树上两点距离改变当且仅当其中恰有一个点是 \(u\) 或 \(v\)(如果两个点恰好分别是 \(u,v\),显然距离不变)。根据上面的讨论,这次操作会使得 \(s_u,s_v\) 中所有元素除去边 \((u,v)\) 异或上 \(w\),而 \(s_u\) 中每个元素除去边 \((u,v)\) 异或上 \(w\) 恰可以得到 \(s_v\),\(s_v\) 中每个元素除去边 \((u,v)\) 异或上 \(w\) 也恰可以得到 \(s_u\)(这个也可以通过分类讨论简要证明),所以交换集合的结论成立。
这是一个很牛逼的模型,有了它我们就可以把题目归约成一个等价条件:
令 \(1\) 为树根,我们把每条边边权下放到其连接的两个点中,深度较大点的点权(边化点)上,然后我们就发现 \(1\) 的点权是 \(0\)。计算 \(1\) 到所有节点的距离 \(dis_i\) 可以通过计算路径点权异或和等效得到,我们交换两个不包含 \(1\) 的节点 \(u,v\) 的距离就相当于交换 \(dis_u,dis_v\)。我们发现我们难以描述对 \((1,u)\) 的操作,那么我们干脆就在 \(1\) 上面再加一个虚拟点,向上连一条虚拟边,这样我们永远都不会对虚拟点进行操作,同时根据原模型这又是正确的。题目有个关键条件:\(n\) 是奇数,意味着原来有奇数个点,而加入的这个虚拟边权就会在异或中被计算奇数次(也就相当于一次)。于是我们有:
右侧 \(dis'_i\) 表示理想状况答案方案希望达到的 \(1\) 到 \(i\) 的距离,这里的 \(x\) 就是 \(1\) 的点权,即 \(1\) 向上连的虚拟边的边权。对于原树,我们虚拟边边权为 \(0\)(因为本来这条边不存在)。对于新树,我们虚拟边边权为 \(x\)。
根据异或的互逆性,移项可得:
然后分别求出 \(dis_i,dis'_i\),判断是否有 \(\forall i,dis_i=dis'_i\) 即可。
总结
我们做了两步关键归约,一是边权化距离(路径异或和)的等效归约,二是边化点与建虚拟边的等效归约。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=1e5+5;
int n;
struct EV{
int idx,head[N];
struct Edge{
int v,next,w;
}adj[N<<1];
void ins(int x,int y,int z){
adj[++idx].v=y;
adj[idx].next=head[x];
adj[idx].w=z;
head[x]=idx;
}
}M1,M2;
int a[N],b[N],suma,sumb;
void dfs0(int u,int fa){
for(int i=M1.head[u];i;i=M1.adj[i].next){
int v=M1.adj[i].v,w=M1.adj[i].w;
if(v==fa)continue;
a[v]=a[u]^w;suma^=a[v];
dfs0(v,u);
}
}
void dfs1(int u,int fa){
for(int i=M2.head[u];i;i=M2.adj[i].next){
int v=M2.adj[i].v,w=M2.adj[i].w;
if(v==fa)continue;
b[v]=b[u]^w;suma^=b[v];
dfs1(v,u);
}
}
int main(){
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n;
for(int i=1;i<n;i++){
int u,v,w1,w2;
cin>>u>>v>>w1>>w2;
M1.ins(u,v,w1);M1.ins(v,u,w1);
M2.ins(u,v,w2);M2.ins(v,u,w2);
}
dfs0(1,0);
dfs1(1,0);
for(int i=1;i<=n;i++)
b[i]^=(suma^sumb);
sort(b+1,b+1+n);
sort(a+1,a+1+n);
for(int i=1;i<=n;i++)
if(a[i]!=b[i]){cout<<"NO";return 0;}
cout<<"YES";
return 0;
}

浙公网安备 33010602011771号