带权并查集,思路很清晰,代码很难看。
对于 I u v ,分以下几种情况不合法。
1.num[u] 已确定 && num[u] != v 。
2.num[u] 的根已确定,若num[u] == v与根节点有冲突。
若合法,则修改num[u] 且 修改num[u]的根节点的信息。
对于 I u v w ,分以下几种情况不合法。
1.num[u] ,num[v] 均已确定或均可通过根节点确定 且 num[u]^num[v] != w;
2.若u,v在一个集合内,且num[u] ^ num[root] ^ num[v] ^num[root] = num[u]^num[v] != w;
若合法,且u,v不在一个集合内,合并u,v所在的集合,若num[root_u]已知,num[root_v]未知(设root_v合并后新集合的根),则更新num[root_v]
。
对于询问:
首先将确定的数的抑或结果计算出来,然后对于剩下的必须符合可以分成X份,每份中必须有偶数个元素。
因为任意两个同根的元素可以由num[u] ^ num[root] ^ num[v] ^num[root] = num[u]^num[v] 得出。
否则输出I don‘t know.
有些题解的解法简直炫酷到没朋友,通过虚拟出一个值为零的节点节省了很多代码,可见预先设计出好的思路是有多重要。
#include <algorithm> #include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> #include <queue> #include <cmath> #include <stack> #include <string> #include <map> #pragma comment(linker, "/STACK:1024000000"); #define EPS (1e-8) #define LL long long #define ULL unsigned long long #define _LL __int64 #define INF 0x3f3f3f3f #define Mod 300 using namespace std; struct N { int fa,re; }st[20010]; int num[20010]; int Find(int x,int &R) { int f = x,re = 0,tre = 0,temp,tf; while(f != st[f].fa) { re ^= st[f].re; f = st[f].fa; } R = re; while(x != st[x].fa) { temp = st[x].re; tf = st[x].fa; st[x].re = re^tre; st[x].fa = f; tre ^= temp; x = tf; } return x; } bool Merge(int u,int v,int w) { int fu,fv,ru,rv; fu = Find(u,ru); fv = Find(v,rv); if(num[fu] != -1) num[u] = num[fu]^ru; if(num[fv] != -1) num[v] = num[fv]^rv; if(num[u] != -1 && num[v] != -1) return (num[u]^num[v]) == w; if(fu == fv) { return (w^ru) == rv; } else { st[fu].fa = fv; st[fu].re = w^rv^ru; if(num[fv] == -1 && num[fu] != -1) { num[fv] = num[fu]^st[fu].re; } } return true; } bool mark[20]; int qu[20]; void JudgeQ(char *s) { int i,j,k = 0; for(i = 0;s[i] < '0' || s[i] > '9'; ++i) ; for(;!(s[i] < '0' || s[i] > '9'); ++i) ; for(;s[i] == ' '; ++i) ; int anw = 0,temp,x; while(s[i] != '\0') { temp = 0; for(;!(s[i] < '0' || s[i] > '9'); ++i) { temp += (s[i]-'0'); temp *= 10; } temp = temp/10 + 1; for(;s[i] == ' '; ++i) ; qu[k++] = temp; } for(i = 0;i < k; ++i) { if(num[qu[i]] != -1) { anw ^= num[qu[i]]; continue; } if(num[Find(qu[i],x)] != -1) { num[qu[i]] = num[Find(qu[i],x)]^x; anw ^= num[qu[i]]; } } memset(mark,false,sizeof(mark)); int ru,rv; for(i = 0;i < k; ++i) { if(mark[i] == false && num[qu[i]] == -1) { for(j = i+1;j < k; ++j) { if(mark[j] == false && num[qu[i]] == -1 && Find(qu[i],ru) == Find(qu[j],rv)) { mark[i] = true,mark[j] = true,anw ^= (ru^rv); break; } } if(mark[i] == false) { printf("I don't know.\n"); return; } } } printf("%d\n",anw); } int Judge(char *s) { int i; for(i = 0;s[i] < '0' || s[i] > '9'; ++i) ; for(;s[i] == ' '; ++i) ; int ans = 0; while(s[i] != '\0') { ans++; for(;!(s[i] < '0' || s[i] > '9'); ++i) ; for(;s[i] == ' '; ++i) ; } return ans; } int main() { int i,n,m,icase = 1; char s[100],ord[100]; int u,v,w; int ans; bool wrong,first; while(scanf("%d %d%*c",&n,&m) && (n||m)) { for(i = 1;i <= n; ++i) st[i].fa = i,st[i].re = 0,num[i] = -1; wrong = false,first = true; ans = 0; printf("Case %d:\n",icase++); while(m--) { gets(s); if(first == false) continue; if(s[0] == 'I') { ans++; if(Judge(s) == 3) { sscanf(s,"%s %d %d %d",ord,&u,&v,&w); u++,v++; if(Merge(u,v,w) == false) wrong = true; } else { sscanf(s,"%s %d %d",ord,&u,&w); u++; if(num[u] == -1 && num[Find(u,v)] == -1) { num[u] = w; num[Find(u,v)] = w^st[u].re; } else if(num[u] == -1) { if((num[Find(u,v)]^st[u].re) != w) wrong = true; else num[u] = w; } else if(num[u] != w) wrong = true; } if(wrong && first) { printf("The first %d facts are conflicting.\n",ans); first = false; } } else { JudgeQ(s); } } printf("\n"); } return 0; }
HDU 3234 Exclusive-OR Regional的题就是硬啊卧槽
时间: 2024-11-07 14:15:13