並查集擴充套件應用 好 uva12232

2021-06-20 16:23:52 字數 1034 閱讀 4105

題意:有兩種操作,乙個是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是朋友,直接合併,如果...