The k-th Largest Group POJ - 2985 treap+並查集

Newman likes playing with cats. He possesses lots of cats in his home. Because the number of cats is really huge, Newman wants to group some of the cats. To do that, he first offers a number to each of the cat (1, 2, 3, …, n). Then he occasionally combines the group cat i is in and the group cat j is in, thus creating a new group. On top of that, Newman wants to know the size of the k-th biggest group at any time. So, being a friend of Newman, can you help him?
Input

1st line: Two numbers N and M (1 ≤ NM ≤ 200,000), namely the number of cats and the number of operations.

2nd to (m + 1)-th line: In each line, there is number C specifying the kind of operation Newman wants to do. If C = 0, then there are two numbers i and j (1 ≤ ij ≤ n) following indicating Newman wants to combine the group containing the two cats (in case these two cats are in the same group, just do nothing); If C = 1, then there is only one number k (1 ≤ k ≤ the current number of groups) following indicating Newman wants to know the size of the k-th largest group.

Output

For every operation “1” in the input, output one number per line, specifying the size of the kth largest group.

Sample Input
10 10
0 1 2
1 4
0 3 4
1 2
0 5 6
1 1
0 7 8
1 1
0 9 10
1 1
Sample Output
1
2
2
2
2
Hint

When there are three numbers 2 and 2 and 1, the 2nd largest number is 2 and the 3rd largest number is 1.


如果把兩組合並 就把他們原來的節點從樹上刪掉 把合併後的節點加入即可 不用擔心編號的改變 

因爲都可以通過並查集查詢到他們的那個最高級別的頭 。

需要用一個變量記錄當前節點數 因爲合併後組數會變少 查詢的時後有可能查詢不到。

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn=200005;
int n;
int pre[maxn];
int num[maxn];
int find(int x)
{
    if(x!=pre[x])pre[x]=find(pre[x]);
    return pre[x];
}
struct node
{
    int l,r,val,size,w;
    int rnd;
}tree[maxn];
int size,root,cc;
int ans[50005];
struct node1
{
    int s,e,id,k;
}p[50005];
void update(int k)
{
    tree[k].size=tree[tree[k].l].size+tree[tree[k].r]
    .size+tree[k].w;
}
void lturn(int &k)
{
    int tmp=tree[k].r;
    tree[k].r=tree[tmp].l;
    tree[tmp].l=k;
    tree[tmp].size=tree[k].size;
    update(k);
    k=tmp;
}
void rturn(int &k)
{
    int tmp=tree[k].l;
    tree[k].l=tree[tmp].r;
    tree[tmp].r=k;
    tree[tmp].size=tree[k].size;
    update(k);
    k=tmp;
}
void insert(int &k,int x)
{
    //cout<<"insert "<<k<<endl;
    if(k==0)
    {
        size++;  //記錄已經使用的結構體數目
        k=size;
        tree[k].val=x;
        tree[k].size=1;
        tree[k].w=1;
        tree[k].rnd=rand();
        return ;
    }
    tree[k].size++;
    if(tree[k].val==x)tree[k].w++;
    else if(x>tree[k].val)
    {
        insert(tree[k].r,x);
        if(tree[tree[k].r].rnd<tree[k].rnd)    //右子樹優先級小於根子樹
            lturn(k);
    }
    else
    {
        insert(tree[k].l,x);
        if(tree[tree[k].l].rnd<tree[k].rnd)
            rturn(k);
    }
}


void del(int &k,int x)
{
    if(k==0)return ;
    //cout<<"del"<<endl;
    if(tree[k].val==x)
    {
        if(tree[k].w>1)
        {
            tree[k].w--;
            tree[k].size--;
            return ;
        }


    if(tree[k].l*tree[k].r==0)k=tree[k].l+tree[k].r;   //如果沒有左右子樹或只有一個
    else if(tree[tree[k].l].rnd<tree[tree[k].r].rnd)
        rturn(k),del(k,x);
    else lturn(k),del(k,x);
    }
    else if(tree[k].val<x)tree[k].size--,del(tree[k].r,x);
    else tree[k].size--,del(tree[k].l,x);
}
void join(int x,int y)
{
    int fx=find(x),fy=find(y);
    if(fx!=fy)
    {
        
        if(num[fx]!=1&&num[fx]!=0)del(root,num[fx]),cc--;
        if(num[fy]!=1&&num[fy]!=0)del(root,num[fy]),cc--;
        pre[fy]=fx;
        num[fx]+=num[fy];
        
        insert(root,num[fx]);
        num[fy]=0;
        cc++;
        
    }
}
int query_num(int k,int x)
{
    if(k==0)return 0;
    //cout<<"rank "<<k<<endl;
    if(x<=tree[tree[k].r].size)
      {
        return query_num(tree[k].r,x);
      }
    else if(x>tree[tree[k].r].size+tree[k].w)
       {


        return query_num(tree[k].l,x-tree[tree[k].r].size
        -tree[k].w);
       }
    else
    {
        return tree[k].val;
    }
}
int main()
{
    int m;
    while(scanf("%d%d",&n,&m)!=-1)
    {
        size=0,root=0;
        cc=0;
        memset(tree,0,sizeof(tree));
        //memset(num,1,sizeof(num));
        for(int i=1;i<=n;i++)
        pre[i]=i,num[i]=1;
        insert(root,1);
        while(m--)
        {
            int op;
            scanf("%d",&op);
            if(op==0)
            {
                int a,b;
                scanf("%d%d",&a,&b);
                join(a,b);
            }
            if(op==1)
            {
                int k;
                scanf("%d",&k);
                int ans=0;
               
                if(cc>=k)ans=query_num(root,k);
                else ans=1;
                printf("%d\n",ans);
            }
        }
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章