P3907 圈的异或(DFS&前缀和)
思路:前缀和。
用一个数组标记结点是否访问过,若的子结点已经被访问过且不是父亲说明形成了一个环,我们还需要用一个数组记录前缀异或和,这里的前缀是相对序说的,且根据异或的性质:如果对于环
搜到时,的子结点被访问过,且已知,显然
若不为0,直接结束,否决继续。
此题的一个坑点是图可能是不连通的,所以可能需要多次。
时间复杂度:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=50+5,M=1e6+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a) memset(a,0,sizeof a)
#define lx x<<1
#define rx x<<1|1
#define reg register
#define PII pair<int,int>
#define fi first
#define se second
int cnt,h[N],vis[N],flag,pre[N],n,m;
struct edge{
int to,nt,w;
}e[N<<1];
void add(int u,int v,int w){
e[++cnt]={v,h[u],w},h[u]=cnt;
}
void dfs(int u,int fa,int s){
vis[u]=1,pre[u]=s;
for(int i=h[u];i;i=e[i].nt){
int v=e[i].to,w=e[i].w;
if(!vis[v]) dfs(v,u,s^w);
else if(pre[u]^pre[v]^w) {
flag=1;
return;
}
}
}
int main(){
int t;
scanf("%d",&t);
while(t--){
scanf("%d%d",&n,&m);
mst(vis),mst(h),mst(pre),cnt=flag=0; //初始化一波.
for(int i=1;i<=m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w),add(v,u,w);
}
for(int i=1;i<=n;i++){ //可能是非连通图.
if(!vis[i]) dfs(i,0,0);
if(flag) break;
}
puts(flag?"No":"Yes");
}
return 0;
}