GT’s Dream
Time Limit: 2000/1000 MS(Java/Others) Memory Limit: 256000/256000K (Java/Others)
Problem Description
在现实中认了无数师傅却毫无长进的GT在梦中成为了某武侠世界的神。在这个世界中初始有n个人,他们各成一派。作为世界神GT总共会进行m次操作,每次操作有如下两种情况
1 x y表示x所在的帮派吞并了y所在的帮派,若x与y本来就处于同一个帮派则该操作无效。
2 k表示GT想要知道当前第k大的帮派有多少人,若当前帮派数量少于k个则输出-1。
Input
第一行输入一个T(T<=10)表示有T组测试数据。
每组数据的第一行包含两个数n,m(n<=100000,m<=300000)表示有n个人,m次操作
接下来m行包含每一次的操作情况。
Output
对于每一个2操作输出当前第k大的帮派有多少人。
Sample Input
1
5 4
1 2 4
1 3 4
2 1
2 2
Sample Output
3
1
【题意】
RT
【思路】
对于合并操作,显然我们可以用并查集。关键在于对第k大的查询。
考虑到每个帮派的人数不会超过100000,我们想到去储存每一个时刻大小为某一人数的帮派个数。
由于每次查询暴力遍历显然会超时,我们想到用线状数组来更新和查询值。
合并时,两个帮派合并成一个,那么可以记为一个帮派的人数为两个帮派之和,还有一个为0,依据此更新数组。
查询时,由于我们用树状数组直接只能查询前缀和,而我们是要从大往小找,于是我们想到用n-前缀和去实现,然后二分即可。
【PS】树状数组下标要从1开始,所以所有操作时都加1处理
#include <cstdio>
#include <cmath>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
#define mst(a,b) memset((a),(b),sizeof(a))
#define rush() int T;scanf("%d",&T);while(T--)
typedef long long ll;
const int maxn = 100005;
const ll mod = 1e9+7;
const ll INF = 1e18;
const double eps = 1e-6;
int n,m;
int a[maxn];
int pre[maxn];
int num[maxn];
char s[maxn];
int tree[maxn];
int lowbit(int x)
{
return x&(-x);
}
int query(int pos)
{
int ans=0;
while(pos>0)
{
ans+=tree[pos];
pos-=lowbit(pos);
}
return ans;
}
void add(int pos,int val)
{
while(pos<maxn)
{
tree[pos]+=val;
pos+=lowbit(pos);
}
}
int find(int x)
{
int t,r=x;
while(pre[x]!=x)
{
x=pre[x];
}
while(r!=x)
{
t=pre[r];
pre[r]=x;
r=t;
}
return x;
}
void join(int a,int b)
{
int A=find(a);
int B=find(b);
if(A==B) return;
add(num[A]+1,-1);
num[A]+=num[B];
add(num[B]+1,-1);
add(num[A]+1,1);
num[B]=0;
add(num[B]+1,1);
pre[B]=A;
}
int main()
{
rush()
{
mst(tree,0);
scanf("%d%d",&n,&m);
for(int i=0; i<=n; i++) pre[i]=i,num[i]=1;
add(2,n);
for(int i=0; i<m; i++)
{
int op;
int x,y;
scanf("%d",&op);
if(op==1)
{
scanf("%d%d",&x,&y);
join(x,y);
}
else
{
scanf("%d",&x);
int ans=0;
int l=1,r=n+1;
while(l<=r)
{
int mid=(l+r)/2;
if(n-query(mid)<x)
{
ans=mid;
r=mid-1;
}
else l=mid+1;
}
if(ans==1) puts("-1");
else printf("%d\n",ans-1);
}
}
}
return 0;
}