排序(並查集 雜湊函式)

2021-07-28 02:55:46 字數 3113 閱讀 1351

【問題描述】
給出乙個包含正整數的陣列p(p1,…,pn),並假設陣列p經過排序後變成陣列q(q1,…,qn)。定義合法替換集合,如果整數對(x,y)屬於合法交換集合,則表示你可以交換陣列p中位置x和位置y的元素。現在有q個操作(詢問),詢問分為以下四種型別:

1.交換位置a和位置b的元素

2.將整數對(a,b)加入到合法交換集合

3.詢問是否能通過合法交換集合中的操作,將陣列p進行排序。(注意:過程中可以以任何順序執行交換操作,並且每個交換操作可以執行任意多次)

4.定義位置對(a,b)是相連的當且僅當位置a的元素可以僅通過合法交換集合中的操作移動到位置b。

定義所有和位置a相連的位置組成的集合為a的群集。如果對於每乙個在a的群集中的位置j,都能通過一系列合法交換集合中的操作使得pj=qj,則稱a的群集是良好的。 你需要回答,有多少對不同的位置對(a,b)滿足:

a)位置a和位置b是不相連的

b)a的群集和b的群集都不是良好的

c)如果我們將位置對(a,b)加入到合法交換集合中,a的群集將變成良好的。

注意:在計算時,位置對(a,b)和位置對(b,a)被視為不同的位置對。

【輸入格式】

第一行兩個正整數,n和q(1<=n, q<=1,000,000)

第二行包含n個正整數p1,…,pn(1<=p1,…,pn<=1,000,000)

接下來q行,每行表示乙個操作:

每行第乙個數字表示操作的種類,(1,2,3或4)

如果操作種類是1或2,後面緊接著兩個正整數a,b(1<=a,b<=n)表示位置對(a,b)

【輸出格式】

對於每乙個詢問(種類為3、4的操作),輸出一行作為詢問的答案。

對於種類為3的詢問的答案輸出「yes」或「no」(不包含雙引號)。「yes」表示能通過合法交換集合的操作將陣列p排序,「no」則表示不能。

對於種類為4的詢問輸出,輸出乙個非負整數表示對應的答案。

【輸入樣例】

【樣例1】

3 5

1 3 2

4 3

2 2 3 4 3

【樣例2】

5 5

4 2 1 4 4

3 4

1 1 3 3 4

【樣例3】

4 10

2 1 4 3

3 4

1 1 2

3 4

2 2 3

2 1 2

4 2 3 4

3 【輸出樣例】

【樣例1】

1 no

0 yes

【樣例2】

no 1

yes

0【樣例3】

no 2

no 1

3 yes

【樣例解釋】

【樣例解釋1】

第乙個詢問答案是1,因為只有位置對(2,3)符合所有的條件,第二個詢問答案是no,因為交換集合為空,數字2和3沒有辦法交換到正確位置,在第三次操作後,我們把位置對(2,3)加入到交換集合中,第四次操作(詢問)答案為0因為2和3已經相連,第五次操作(詢問)答案是yes,因為可以通過位置對(2,3)把陣列排好序。

【資料範圍】

50%的資料滿足n,q<=1000。

【**】

這道題一看就知道是並查集,但具體怎麼做就難了。

要定義乙個雜湊函式,來不重複的代表每個數的權值。

然後定義2個陣列。

q(i)表示p中i這個並查集所代表的位置的元素的權值和。

p(i)表示q中i這個並查集所代表的位置的元素的權值和。

然後用map存每個p(i)-q(i)的值。

當我們要找互相配合起來和諧的並查集時就直接找2個差值加起來為0的就可以了,在中間邊變化邊記錄就好。

而要全部和諧就得所有差值都為0,直接看map中為0的個數是不是n個就可以了。

其他就是並查集了。

具體**如下:

#include

#include

#include

#include

#include

#include

using namespace std;

typedef long long ll;

const int maxn=1000005;

const ll mod=2000005ll;

ll q[maxn],p[maxn],a[maxn];

mapint>mp;

int n,m,b[maxn],pa[maxn],c[maxn];

int num=0,size[maxn];

int find(int

x)void un(int

x,int

y)int

read()

returnx;}

int main()

intx,id,y,px,py;

for(int i=1;i<=n;i++)

sort(b+1,b+1+n);

for(int i=1;i<=n;i++)

while(m--)

mp[p[px]-q[px]]-=size[px];

if(q[px]-p[px]!=0) num-=size[px]*mp[q[px]-p[px]];

mp[p[py]-q[py]]-=size[py];

if(q[py]-p[py]!=0)num-=size[py]*mp[q[py]-p[py]];

q[px]+=a[c[y]]-a[c[x]];

q[py]+=a[c[x]]-a[c[y]];

mp[p[px]-q[px]]+=size[px];

if(q[px]-p[px]!=0)num+=size[px]*mp[q[px]-p[px]];

mp[p[py]-q[py]]+=size[py];

if(q[py]-p[py]!=0)num+=size[py]*mp[q[py]-p[py]];

swap(c[x],c[y]);

}if(id==2)

if(id==3)

if(id==4)

}return

0;}

並查集 並查集

本文參考了 挑戰程式設計競賽 和jennica的github題解 陣列版 int parent max n int rank max n void init int n int find int x else void union int x,int y else 結構體版 struct node ...

並查集Find函式

void find int x int find int x while p x return x 並查集的應用有很多這裡給大家推薦一道很好的題。這道題的 如下 int pre maxn maxx maxn num maxn int find int x while p x return x voi...

並查集入門(普通並查集 帶刪除並查集 關係並查集)

什麼是並查集?通俗易懂的並查集詳解 普通並查集 基礎並查集 例題 題解 how many tables problem description lh boy無聊的時候很喜歡數螞蟻,而且,還給每乙隻小螞蟻編號,通過他長期的觀察和記錄,發現編號為i的螞蟻會和編號為j的螞蟻在一起。現在問題來了,他現在只有...