排序(並查集&&雜湊函式)

細雨欣然發表於2017-03-08
【問題描述】  

  給出一個包含正整數的陣列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。

【來源】

https://jzoj.net

這道題一看就知道是並查集,但具體怎麼做就難了。
要定義一個雜湊函式,來不重複的代表每個數的權值。
然後定義2個陣列。
q(i)表示P中i這個並查集所代表的位置的元素的權值和。
p(i)表示Q中i這個並查集所代表的位置的元素的權值和。
然後用map存每個p(i)-q(i)的值。
當我們要找互相配合起來和諧的並查集時就直接找2個差值加起來為0的就可以了,在中間邊變化邊記錄就好。
而要全部和諧就得所有差值都為0,直接看map中為0的個數是不是n個就可以了。
其他就是並查集了。

具體程式碼如下:

#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
typedef long long ll;
const int maxn=1000005;
const ll mod=2000005ll;

ll q[maxn],p[maxn],a[maxn];
map<ll,int>mp;
int n,m,b[maxn],pa[maxn],c[maxn];
int num=0,size[maxn];

int find(int x){return pa[x]==x?x:pa[x]=find(pa[x]);}

void un(int x,int y)
{
    int px=find(x),py=find(y);
    if(px==py) return;
    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]+=q[py];
    p[px]+=p[py];
    size[px]+=size[py];
    if(q[px]-p[px]!=0) num+=size[px]*mp[q[px]-p[px]];
    mp[p[px]-q[px]]+=size[px];
    pa[py]=px;
}

int read()
{
    int x=0;
    char ch=getchar();
    while(ch<'0'||ch>'9') ch=getchar();
    while(ch>='0'&&ch<='9') 
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x;
}
int main()
{
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    n=read();m=read();
    a[1]=17;
    for(int i=2;i<=1000000;i++)
    {
        a[i]=(a[i-1]*17)%mod;
    }
    int x,id,y,px,py;
    for(int i=1;i<=n;i++)
    {
        c[i]=b[i]=read();
        q[i]=a[b[i]];
        pa[i]=i;
        size[i]=1;
    }
    sort(b+1,b+1+n);
    for(int i=1;i<=n;i++) 
    {
        p[i]=a[b[i]];
        if(q[i]-p[i]!=0)num+=mp[q[i]-p[i]];
        mp[p[i]-q[i]]++;
    }
    while(m--)
    {
        id=read();
        if(id==1)
        {
            x=read();y=read();
            px=find(x),py=find(y);
            if(px==py)
            {
                swap(c[x],c[y]);
                continue;
            }
            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)
        {
            x=read();y=read();
            un(x,y);
        }
        if(id==3)
        {
            if(mp[0]==n) printf("YES\n");
            else printf("NO\n");
        }
        if(id==4)
        {
            printf("%d\n",num);
        }
    }
    return 0;
}

相關文章