1. 程式人生 > >poj1985 The k-th Largest Group

poj1985 The k-th Largest Group

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

題解:平衡樹。用並查集合並,刪除兩個點,同時把兩個點相加放入平衡樹。

程式碼(splay):

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
int num[1000000],g[1000000],size[1000000],cnt[1000000],lc[1000000],rc[1000000],fa[1000000],val[1000000],root,tot;
void clear(){  
    root=tot=0;  
    memset(size,0,sizeof(size));  
    memset(cnt,0,sizeof(cnt));  
}  
void updata(int x){  
    if(x){  
        size[x]=cnt[x]+(lc[x]?size[lc[x]]:0)+(rc[x]?size[rc[x]]:0);  
    }  
}  
void zig(int x){  
    int y,z;  
    if(!fa[x])return;  
    y=fa[x];z=fa[y];  
    if(z)  
        if(lc[z]==y)lc[z]=x;  
         else rc[z]=x;  
        fa[x]=z;fa[y]=x;fa[rc[x]]=y;lc[y]=rc[x];rc[x]=y;  
        updata(y);updata(x);  
}  
void zag(int x){  
    int y,z;  
    if(!fa[x])return;  
    y=fa[x];z=fa[y];  
    if(z)  
     if(lc[z]==y)lc[z]=x;  
      else rc[z]=x;  
     fa[x]=z;fa[y]=x;fa[lc[x]]=y;rc[y]=lc[x];lc[x]=y;  
     updata(y);updata(x);   
}  
void splay(int &root,int x){  
    int y,z;  
    while(fa[x]){  
        y=fa[x];z=fa[y];  
        if(z){  
            if(lc[z]==y&&lc[y]==x)zig(y),zig(x);  
             else if(lc[z]==y&&rc[y]==x)zag(x),zig(x);  
              else if(rc[z]==y&&lc[y]==x)zig(x),zag(x);  
               else zag(y),zag(x);  
        }  
         else if(lc[y]==x)zig(x);  
          else zag(x);  
    }  
    root=x;  
}  
void sp(int x){  
    splay(root,x);  
}  
void insert(int &k,int key,int p){  
    if(!k){  
        size[k=++tot]=cnt[k]=1;  
        lc[k]=rc[k]=0;  
        val[k]=key;  
        fa[k]=p;  
        sp(k);  
        return;  
    }  
    size[k]++;  
    if(key==val[k]){  
        cnt[k]++;  
        return;  
    }  
    if(key<val[k])insert(lc[k],key,k);  
     else insert(rc[k],key,k);  
}  
void ins(int key){  
    if(!root){  
        size[root=++tot]=cnt[root]=1;  
        lc[root]=rc[root]=0;  
        val[root]=key;fa[root]=0;  
        return;  
    }  
    insert(root,key,0);  
}  
int find(int k,int key){  
    while(k){  
        if(val[k]==key)break;  
        k=key<val[k]?lc[k]:rc[k];  
    }  
    if(k)sp(k);  
    return k;  
}  
int fin(int key){  
    return find(root,key);  
}  
int getmin(int k){  
    return lc[k]?getmin(lc[k]):k;  
}  
int getmax(int k){  
    return rc[k]?getmax(rc[k]):k;  
}  
void del(int key){  
    int ls,rs,x,lson;  
    x=fin(key);ls=lc[x];rs=rc[x];  
    if(!x)return;  
    if(--cnt[x])return;  
    if(!ls&&!rs){  
        clear();  
        return;  
    }  
    if(!ls)root=rs,fa[rs]=0;  
     else if(!rs)root=ls,fa[ls]=0;  
      else{  
        lson=getmax(ls);  
        swap(lson,ls);  
        fa[lson]=0;sp(ls);  
        rc[ls]=rs;fa[rs]=ls;updata(ls);  
      }  
}  
int findkth(int k){  
    int t;  
    t=root;  
    while(t){  
        if(size[lc[t]]<k&&k<=size[lc[t]]+cnt[t])break;  
        if(k<=size[lc[t]])t=lc[t];  
         else k-=size[lc[t]]+cnt[t],t=rc[t];  
    }  
    sp(t);  
    return t;  
}  
int findd(int t){
	if(t==g[t])return t;
    g[t]=findd(g[t]);
    return g[t];
}
int main(){
	int n,m,i,t1,t,k,x,y;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++)g[i]=i,num[i]=1;
	for(i=1;i<=n;i++)ins(1);
	for(i=1;i<=m;i++){
		scanf("%d",&t1);
		if(t1==0){
			scanf("%d%d",&t,&k);
			x=findd(t);y=findd(k);
			if(x!=y){
				g[x]=y;
				del(num[x]);del(num[y]);
				num[y]+=num[x];
				ins(num[y]);
				n--;
			}
		}
		 else{
		 	scanf("%d",&t);
		 	printf("%d\n",val[findkth(n-t+1)]);
		 }
	}
}