P3907 圈的異或(DFS&前綴和)

P3907 圈的異或(DFS&前綴和)

傳送門

思路:dfs+dfs+前綴和。

用一個數組vis[]vis[]標記結點是否訪問過,若uu的子結點vv已經被訪問過且不是父親說明形成了一個環,我們還需要用一個pre[]pre[]數組記錄前綴異或和,這裏的前綴是相對dfsdfs序說的,且根據異或的性質:如果對於環abcdba\rightarrow b\rightarrow c\rightarrow d\rightarrow b

搜到dd時,dd的子結點bb被訪問過,且已知pre[b],pre[d]pre[b],pre[d],顯然xor(b,c,d)=pre[b]pre[d]wd,bxor(b,c,d)=pre[b]\oplus pre[d]\oplus w_{d,b}

xor(b,c,d)xor(b,c,d)不爲0,直接結束,否決繼續dfsdfs

此題的一個坑點是圖可能是不連通的,所以可能需要多次dfsdfs

時間複雜度:O(n+m)O(n+m)

#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章