POJ 2985 The k-th LargestGroup(Treap+并查集)

题意:

N只猫,开始每只猫都是一个小组,下面要执行M个操作。

操作0 i j  是把i猫和j猫所属的小组合并。

操作1 k  是问你当前第k大的小组大小是多少. k<=当前的最大组数.

 

题解:

      Treap实现名词树+并查集,并查集根节点rootpa[root] = -规模。

/**
   treap求第k大
*/

#include<cstdlib>
#include<cstring>
#include<cstdio>

using namespace std;

const int maxn = 2e5+999;
int n,m,cnt;
int pa[maxn]; /**并查集*/

struct node
{
    node* ch[2];
    int r,v,s;
    node(int v):v(v)
    {
        r = rand();
        s = 1;
        ch[0] = ch[1] = NULL;
    }

    void maintain()
    {
        s = 1;
        if(ch[0])s+=ch[0]->s;
        if(ch[1])s+=ch[1]->s;
    }

    int cmp(int x)
    {
        if(x==v)return -1;
        return x<v?0:1;
    }
}*root;


void Rotate(node* &o,int d)
{
    node *k = o->ch[d^1];
    o->ch[d^1] = k->ch[d];
    k->ch[d] = o;
    o->maintain();
    k->maintain();
    o=k;
}

void Insert(node* &o,int v)
{
    if(o==NULL)o = new node(v);
    else
    {
        int d = v<o->v? 0:1;
        Insert(o->ch[d],v);
        if(o->ch[d]->r > o->r)
            Rotate(o,d^1);
    }
    o->maintain();
}

void Remove(node* &o,int v)
{
    int d = o->cmp(v);
    if(d == -1)
    {
        if(o->ch[0] && o->ch[1])
        {
            int d2 = o->ch[0]->r < o->ch[1]->r? 0 : 1;
            Rotate(o,d2);
            Remove(o->ch[d2],v);
        }
        else
        {
            node* u = o;
            if(!o->ch[0])o=o->ch[1];
            else o = o->ch[0];
            delete u;
        }
    }
    else Remove(o->ch[d],v);
    if(o) o->maintain();
}

int kth(node *o,int k)///第k大
{

    int s = (o->ch[1]==NULL)?0:o->ch[1]->s;
    if(k==s+1)return o->v;
    else if(k<=s)return kth(o->ch[1],k);
    else return kth(o->ch[0],k-s-1);
}

///并查集部分
int findset(int x)
{
    return pa[x]<0? x : pa[x] = findset(pa[x]);
}
void unionset(int x,int y)
{
    int rx = findset(x);
    int ry = findset(y);
    if(rx != ry)
    {
        if(pa[rx]!=-1){Remove(root,-pa[rx]);cnt--;}/**根节点的pa放集合内元素数量的相反数*/
        if(pa[ry]!=-1)Remove(root,-pa[ry]),cnt--;
   
        Insert(root,-pa[rx]-pa[ry]);
        cnt++;
        pa[ry] += pa[rx];
        pa[rx] = ry;
    }
}

int main()
{
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        root = NULL;
        cnt = 0;
        memset(pa,-1,sizeof pa);
        while(m--)
        {
            int op,i,j,k;
            scanf("%d",&op);
            if(op==0)
            {
                scanf("%d%d",&i,&j);
                unionset(i,j);
            }
            else
            {
                scanf("%d",&k);
                if(k>cnt)printf("1\n");
                else 
                printf("%d\n",kth(root,k));
            }
        }

    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/sgh666666/article/details/80433376