原题链接:UVA12232 Exclusive-OR - 洛谷 或者 Exclusive-OR - UVA 12232 - Virtual Judge
题解:
带权并查集处理异或运算。
首先,对于第二种情况,I a b v 我们可以将a,b连起来形成一个并查集,同时用一个value数组存储当前节点异或头节点的 的值,此时我们关注的就是不同头节点连接时value数组的更新。
我们思考此时有个一条输入 I a b v ;a 对应的头节点为La,b对应头节点为Lb,假设La挂到Lb上,则
value[La]=value[a]^value[b]^v=a^La ^ b^Lb ^ a^b = La^Lb
这时我们就推出了不同集合之间的更新关系。
接着,我们处理赋值情况,显而易见的是,当一个集合内的一个值确定,那么集合内的其他值都确定(因为我们知道他们的异或关系),这里只需要设置一个虚拟节点即可。
最后,查询过程,如果此时读入一个虚拟节点内的值,那么我们知晓其确切的值,无需处理;但是如果读入的是其余集合内的值,假设为 ai 那么我们只能知晓 ai^fa[ai] 的值,我们不难发现要利用当前集合内的另一个值将fa[ai]的影响消除。
因此,我们得到结论,虚拟节点集合内直接取出对应value,其余集合内要取偶数个才能得到答案。得解。
PS:这道题输出有点坑,首先 I don't know. 中 ‘ 得是英文状态下的;其次,每一组输出后面要额外多一行空行。
code:
#include<bits/stdc++.h> using namespace std; const int N=2e4+5; int fa[N],value[N]; int n,q,t=0;int find_dsu(int tree){if (tree!=fa[tree]){int t=fa[tree];fa[tree]=find_dsu(t);value[tree]^=value[t];}return fa[tree]; }void union_dsu(int l,int r,int v){int lf=find_dsu(l),rf=find_dsu(r);if (lf==n){fa[rf]=n;value[rf]=(value[l]^value[r]^v); // cout<<rf<<" "<<value[l]<<" "<<value[r]<<" "<<v<<"\n";return;}if (rf==n){fa[lf]=n;value[lf]=(value[l]^value[r]^v);return;}fa[lf]=rf;value[lf]=(value[l]^value[r]^v); }int main(){ // freopen("input.txt","r",stdin);string s;while (cin>>n>>q){if (n==0 && q==0) break;cout<<"Case "<<++t<<":\n";for (int i=0;i<=n;i++){fa[i]=i;value[i]=0;}int now_q=0;bool is_print=true;while(q--){cin>>s;if (s[0]=='I'){getline(cin,s);s=s+" ";int cnt_s=s.size();now_q++;int a[3]={0,0,0},l=0;for (int i=1;i<cnt_s;i++){if (s[i]==' '){l++;}else{a[l]=a[l]*10+s[i]-'0';}}// for (int i=0;i<l;i++) cout<<a[i]<<" "; // cout<<"\n";if (l==2){int f=find_dsu(a[0]);if (f!=n) union_dsu(n,a[0],a[1]);else if (value[a[0]]!=a[1]){cout<<"The first "<<now_q<<" facts are conflicting.\n";is_print=false;}}else{int lf=find_dsu(a[0]),rf=find_dsu(a[1]);if (lf!=rf) union_dsu(a[0],a[1],a[2]);else if ((value[a[0]]^value[a[1]])!=a[2]){cout<<"The first "<<now_q<<" facts are conflicting.\n";is_print=false;}}}else{// for (int i=0;i<=n;i++){ // cout<<i<<" "<<fa[i]<<" "<<value[i]<<"\n"; // }int k;cin>>k;int ans=0;int now;map<int ,int > num;for (int i=1;i<=k;i++){cin>>now;int f=find_dsu(now);if (f!=n) num[f]++;ans^=value[now];}if (is_print==false) continue;bool bol=true;for (auto it : num){if (it.second%2) bol=false;}if (bol) cout<<ans<<"\n";else cout<<"I don't know.\n";} }cout<<"\n";}return 0; }