解题报告: luogu P3907
题目链接:P3907 圈的异或
sb 题,但还是没做出来。
核心思想是 \(dfs\) 对于不是继承节点的已经扫过的点如果被连接就形成环。
异或可以用前缀和来处理。
借助一个定理:
\[a \;\text{xor}\; b\; \text{xor}\; b=a
\]
直接把前面的再异或掉即可。
然而不过样例。
?????
因为可能有自环,更恐怖的是 \(dfs\) 起点的自环。
怎么处理呢?
方法一:特判。
不多说了。
方法二:起始 \(dfs\) 的父节点不是自己就好了,比如说 \(n+1\),\(-1\),\(0\) 之类的。
复杂的应该是 \(\mathcal O(T(n+m))\)。
\(Code:\)
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define read(x) scanf("%d",&x)
#define MAXN 55
struct node
{
int to,nxt,w;
}e[MAXN<<1];
int head[MAXN],cnt=0;
int T,n,m,x,y,c;
int sum[MAXN],vis[MAXN];
bool ans=true;
void add(int u,int v,int z)
{
e[++cnt].to=v;
e[cnt].nxt=head[u];
e[cnt].w=z;
head[u]=cnt;
return;
}
void clear()
{
memset(e,0,sizeof(e)),memset(head,0,sizeof(head)),cnt=0;
memset(sum,0,sizeof(sum)),memset(vis,0,sizeof(vis));
ans=true;
return;
}
void dfs(int cur,int fa)
{
vis[cur]=1;
for(int i=head[cur];i;i=e[i].nxt)
{
int j=e[i].to;
if(j==fa) continue;
if(!vis[j]) sum[j]=sum[cur]^e[i].w,dfs(j,cur);
else
{
int now=sum[cur]^sum[j]^e[i].w;
if(now){ans=false;return;}
}
}
return;
}
int main()
{
read(T);
while(T--)
{
clear();
read(n),read(m);
for(int i=1;i<=m;i++)
{
read(x),read(y),read(c);
add(x,y,c);
add(y,x,c);
}
for(int i=1;i<=n;i++)
{
if(!vis[i])
{
dfs(i,0);
if(!ans){puts("No");break;}
}
}
if(ans) puts("Yes");
}
return ~~0;
}