標籤:style os io for cti ar 代碼 amp
帶權並查集,思路很清晰,代碼很難看。
對於 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 300using 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;}