思路:
首先,对于每个员工之间的合并,可以采用并查集来解决这件事.那么主要的问题就是如何求这个集合中第k大的数.这里采用权值线段树来合并,大体的权值线段树,就是我们当时用来求逆序数的用法。
题目中是2e5的数据范围,那么我们初始对每个员工建立一个树,然后记录下他的根节点和他的左右子节点,合并时,将两个团队所在树的根节点的合并就好,
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
const int maxn=1e5+10;
const int maxm=1e7+10;
struct node
{
int ls,rs,sum;
int l,r;
}q[maxm];
int a[maxn],father[maxn],root[maxn],s[maxn];
int n,m;
int k;
int build(int l,int r,int d)//建树
{
k++;
int t=k;
q[t].l=l,q[t].r=r;
if(r<d||l>d)
{
q[t].ls=0,q[t].rs=0,q[t].sum=0;
return t;
}
else
{
q[t].sum=1;
if(l==r)
{
q[t].ls=0,q[t].rs=0;
return t;
}
int mid=(l+r)>>1;
q[t].ls=build(l,mid,d);
q[t].rs=build(mid+1,r,d);
return t;
}
}
int find(int x)
{
return x==father[x]?x:father[x]=find(father[x]);
}
int get(int roots,int ss)//找第k大的数
{
if(q[roots].l==q[roots].r)
return q[roots].l;
int ls=q[roots].ls,rs=q[roots].rs;
if(q[ls].sum<ss)
return get(rs,ss-q[ls].sum);
else
return get(ls,ss);
}
int merge(int x,int y)//合并
{
if(q[x].ls==0)
q[x].ls=q[y].ls;
else
{
if(q[y].ls>0)
{
q[x].ls=merge(q[x].ls,q[y].ls);
}
}
if(q[x].rs==0)
q[x].rs=q[y].rs;
else
{
if(q[y].rs>0)
{
q[x].rs=merge(q[x].rs,q[y].rs);
}
}
q[x].sum+=q[y].sum;
return x;
}
int main()
{
while(scanf("%d %d",&n,&m)!=EOF)
{
int maxl=inf,maxr=0;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
maxl=min(maxl,a[i]);
maxr=max(maxr,a[i]);
}
k=0;
for(int i=1;i<=n;i++)
{
father[i]=i;
s[i]=1;
root[i]=build(maxl,maxr,a[i]);
}
while(m--)
{
int x,y;
int cnd;
scanf("%d",&cnd);
if(cnd==2)
{
scanf("%d %d",&x,&y);
int fx=find(x),fy=find(y);
s[fx]+=s[fy];
father[fy]=fx;
root[fx]=merge(root[fx],root[fy]);
}
else
{
scanf("%d",&x);
int fx=find(x);
printf("%d\n",get(root[fx],(s[fx]+1)>>1));
}
}
}
return 0;
}