HRBUST - 2371
题意:在现实中认了无数师傅却毫无长进的GT在梦中成为了某武侠世界的神。在这个世界中初始有n个人,他们各成一派。作为世界神GT总共会进行m次操作,每次操作有如下两种情况
1 x y 表示x所在的帮派吞并了y所在的帮派,若x与y本来就处于同一个帮派则该操作无效。
2 k 表示GT想要知道当前第k大的帮派有多少人,若当前帮派数量少于k个则输出-1。
题解:每次如果两个集合合并就分别让两个集合所属的权值线段树区间减1,而合并的大集合所对应的区间加1,不过并查集要用优化版的(也就是将并查集压缩一下,将树压矮一点)
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int maxn=100005;
int sum[maxn<<2];
int p[maxn],num[maxn];
int n,m,pren;
void build(int l,int r,int rt)
{
if(l==r){
if(l==1)
sum[rt]=n;
return;
}
int mid=(l+r)>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
int finds(int x)
{
//return x==p[x]?x:finds(p[x]);
if(x==p[x]){
return x;
}
else{
int px=finds(p[x]);
p[x]=px;
return px;
}
}
void update1(int l,int r,int rt,int x)
{
if(l==r){
sum[rt]-=1;
return;
}
int mid=(l+r)>>1;
if(x<=mid){
update1(l,mid,rt<<1,x);
}
else{
update1(mid+1,r,rt<<1|1,x);
}
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
void update2(int l,int r,int rt,int x)
{
if(l==r){
sum[rt]+=1;
return ;
}
int mid=(l+r)>>1;
if(x<=mid){
update2(l,mid,rt<<1,x);
}
else{
update2(mid+1,r,rt<<1|1,x);
}
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
int query(int l,int r,int rt,int k)
{
if(l==r){
return l;
}
int mid=(l+r)>>1;
if(sum[rt<<1]>=k){
return query(l,mid,rt<<1,k);
}
else{
return query(mid+1,r,rt<<1|1,k-sum[rt<<1]);
}
}
inline int read()
{
register int x=0,t=1;
register char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
if(ch=='-'){t=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
return x*t;
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
//memset(sum,0,sizeof(sum));
for(int i=1;i<=4*n;i++){
sum[i]=0;
}
scanf("%d%d",&n,&m);
pren=n;
for(int i=1;i<=n;i++){
p[i]=i;num[i]=1;
}
build(1,n,1);
/*for(int i=1;i<=4*n;i++){
printf("%d ",sum[i]);
}
printf("\n");*/
int op,x,y,dx,dy;
while(m--){
scanf("%d",&op);
if(op==1){
x=read();
y=read();
//scanf("%d%d",&x,&y);
dx=finds(x);
dy=finds(y);
//printf("koo\n");
// printf("%d %d\n",num[dx],num[dy]);
if(dx!=dy){
// printf("dx:%d dy:%d\n",dx,dy);
// printf("num[dx]:%d num[dy]:%d\n",num[dx],num[dy]);
update1(1,n,1,num[dx]);
update1(1,n,1,num[dy]);
update2(1,n,1,num[dx]+num[dy]);
p[dx]=dy;
num[dy]+=num[dx];
//printf("num[dx]:%d num[dy]:%d\n",num[dx],num[dy]);
pren--;
}
}
else{
scanf("%d",&x);
if(x>pren){
printf("-1\n");
}
else{
printf("%d\n",query(1,n,1,pren+1-x));
}
}
/*for(int i=1;i<=4*n;i++){
printf("%d ",sum[i]);
}
printf("\n");
printf("pren:%d\n",pren);*/
}
}
return 0;
}