題意:有兩種操作,乙個是i p q v告訴你 x[p]^x[q]=v,乙個是查詢k個數的異或和,問是否出現矛盾以及能否確定答案
很經典的並查集問題
首先我們可以虛擬乙個根節點x[n]=0,這樣所有的i p v都可以轉換成 x[p]^x[n]=0.另w[a]=x[a]^x[f[a]]即本身和父節點的異或值, 那麼如何合併呢?記fp=f[p],fq=f[q],x[p]^x[q]=v,另f[fp]=fq的話,w[fp]=x[fp]^x[fq]=(x[p]^x[fp])^(x[p]^x[q])^(x[q]^x[fq])=w[p]^v^w[q],由此合併。難點在查詢。x[a1]^x[a2]^...^x[ak]=w[a1]^w[a2]^..^w[ak]^x[f[a1]]^x [f[a2]]^...^x[f[ak]],前一部分直接求即可,後一部分只需求父節點出現次數為奇數次的,異或起來即可
#include#include#include#includeusing namespace std;
const int maxn=20005;
int pra[maxn],val[maxn];
int n,q,k,cas2;
char s[20];
bool flag1,flag2;
int find(int x)
void unite(int p,int q,int v)
if(x==n)swap(x,y);
pra[x]=y;
val[x]=val[p]^v^val[q];
}int main()
if(flag1)continue;
map::iterator i;
for(i=m.begin();i!=m.end();i++)
if((i->second%2)&&(i->first!=n))
if(!flag2)printf("i don't know.\n");
else printf("%d\n",ans);}}
printf("\n");
}return 0;
}
詳解 並查集高階技巧 加權並查集 擴充套件域並查集
可以理解為使用陣列實現的樹形結構,只儲存了每個節點的父節點 前驅 功能為 合併兩個節點 及其所在集合 查詢節點所屬集合的代表節點 可以理解為根節點 以6個元素為例 編號0到5 把0單獨劃分為乙個集合 把1,2,3,4劃分為乙個集合 把5單獨劃分為乙個集合。n個元素的並查集,只需要乙個容量為n的陣列f...
True Liars 擴充套件域並查集
傳送門 每個點拆成兩個,表示好人或壞人 我們合併集合後,發現存在幾組對立的集合 也就是說這個集合和與它對立的集合只能選乙個 我們用rt1 i rt2 i 表示第i個集合 和 與第i個集合對立的集合 cnt1,cnt2表示該集合好人的個數 用f i j 表示到第i個集合,好人為j的方案數 同時記錄fr...
並查集的擴充套件域
核心思想 fa a 儲存與a同類的 fa a 1 n 儲存與a發生第一類關係的 fa a 2 n 儲存與a發生第二類關係的 fa a 3 n 儲存與a發生第三類關係的 分析將並查集中儲存節點關係的f陣列擴大2倍,1 n表示朋友,n 1 2 n表示敵人。那麼對於x,y,如果x和y是朋友,直接合併,如果...