题解:P11170 「CMOI R1」图上交互题 / Constructive Minimum Xor Path
路径分析
首先题目规定路径可以经过重复点和重复边。我们考虑能否优化这种叙述。走过的边无非就两种情况:
1、该边被经过了奇数次,根据异或的性质,这种情况等价于该边只走了一次。
2、该边被经过了偶数次。对于一幅图,我们删去其中经过偶数次的边,然后由于每个偶数边的进入离开次数都为偶数,我们可以把这些进入和出去的边两两相连,直到图中没有偶数边为止,这样一直操作过后走过的路径依然合法。根据异或的性质,偶数边的代价记为
以下图为例,其中黑色的箭头代表原来经过的情况,那么红色的
特殊图分析
根据以上两条性质,我们仅需要考虑简单路径即可 (指每条边仅被经过一次)。
有了以上的性质,我们考虑这张图为树的情况,那么一个合法的构造方案显然可以将各个边的长度
题目中的图与树不同的本质在于有环,因此我们考虑简单环,记一个环上各个边的
接下来考虑必要性,假设
结论
最后将环和树结合起来考虑,可以将题目中给定的图视作一棵树和若干环构成,我们可以在遍历树上节点的时候找到环,运用类似树上差分的操作,计算出每个环的异或长度,判断该异或值是否为
结合下图理解,其中蓝色代表
code
最丑的环节:
#include<bits/stdc++.h>
#define INF 0x7fffffff
typedef long long ll;
using namespace std;
const int N=1e6+6;
int n,m,tot=0,head[N],a[N];
struct node{
int nxt,to,w;
}e[N<<2];
void addEdge(int u,int v,int w){
e[++tot]=(node){head[u],v,w};
head[u]=tot;
e[++tot]=(node){head[v],u,w};
head[v]=tot;
}
int dis[N];
bool ans=1;
void dfs(int u){
for(int i=head[u];i;i=e[i].nxt){
int v=e[i].to;
if(dis[v]!=-1){
if(dis[u]^e[i].w^dis[v]) ans=0;
continue;
}
dis[v]=dis[u]^e[i].w;
dfs(v);
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1,x,y,z;i<=m;i++){
scanf("%d%d%d",&x,&y,&z);
addEdge(x,y,z); a[i]=z;
}
for(int i=1;i<=n;i++) dis[i]=-1;
for(int i=1;i<=n;i++){
if(dis[i]==-1){
dis[i]=0;
dfs(i);
}
}
if(ans){
puts("Yes");
for(int i=1;i<=m;i++) printf("%d ",a[i]);
}else puts("No");
return 0;
}
这是蒟蒻的第一篇题解,如有不足,欢迎指正。