题解 P5651 【基础最短路练习题】

StudyingFather

2019-11-13 18:57:54

Solution

一道非常棒的思维题。 首先考虑没有环的情况,这时候我们随便取一个点作为根节点进行 DFS,求出每个点 $i$ 到根节点路径的权值 $dis_i$。 这时候 $u$ 到 $v$ 路径的权值显然为 $dis_u \oplus dis_v$。 接下来考虑有环的情况。 题目中给的图性质非常特殊:保证 $G$ 中不存在简单环使得边权异或和不为 $0$,也即所有环的权值均为零。 这意味着,如果我们把一个环分割为两段,这两段的权值相等(否则环的权值就不为 $0$ 了)。 因此假如从 $u$ 到 $v$ 的路径经过了一个环,我们只需保留环的其中一段即可(另外一段和这一段是一样的)。 这样,我们求出图的任意一个生成树,就可以把问题转化为树的情况。 到此,问题得到了完美解决。 ```cpp #include <cstdio> struct edge { int v,w,next; }e[400005]; int fa[100005],head[100005],dis[100005],cnt; void addedge(int u,int v,int w) { e[++cnt].v=v; e[cnt].w=w; e[cnt].next=head[u]; head[u]=cnt; } int find(int x) { return fa[x]==x?x:fa[x]=find(fa[x]); } void unionn(int x,int y) { fa[y]=x; } void dfs(int u,int fa,int w) { dis[u]=w; for(int i=head[u];i;i=e[i].next) if(e[i].v!=fa) dfs(e[i].v,u,w^e[i].w); } int main() { int n,m,q; scanf("%d%d%d",&n,&m,&q); for(int i=1;i<=n;i++) fa[i]=i; for(int i=1;i<=m;i++) { int u,v,w; scanf("%d%d%d",&u,&v,&w); int fu=find(u),fv=find(v); if(fu!=fv) { unionn(fu,fv); addedge(u,v,w); addedge(v,u,w); } } dfs(1,0,0); while(q--) { int u,v; scanf("%d%d",&u,&v); printf("%d\n",dis[u]^dis[v]); } return 0; } ```