链接:http://poj.org/problem?id=2985
题意:给你n,m,代表有n个集合,开始每个集合大小为1,接下来m个操作,每个操作先输入c,c==0则将x,y集合合并,c==0,输出第k大。
分析:集合和并可以用并查集,然后求第k大直接用树状数组。
代码:
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<string>
#include<vector>
#include<queue>
#include<cmath>
#include<stack>
#include<set>
#include<map>
#define INF 0x3f3f3f3f
#define Mn 200005
#define Mm 2000005
#define mod 1000000007
#define CLR(a,b) memset((a),(b),sizeof((a)))
#define CPY(a,b) memcpy ((a), (b), sizeof((a)))
#pragma comment(linker, "/STACK:102400000,102400000")
#define ul u<<1
#define ur (u<<1)|1
using namespace std;
typedef long long ll;
int bit[Mn];
int n;
int lowbit(int x) {
return x&(-x);
}
int sum(int x) {
int sum=0;
while(x>0) {
sum+=bit[x];
x-=lowbit(x);
}
return sum;
}
void push(int pos,int num) {
while(pos<=n) {
bit[pos]+=num;
pos+=lowbit(pos);
}
}
int kth(int k) {
int num=0;
int x=0;
for(int i=1<<18; i>0; i>>=1) {
num+=i;
if(num>=n||x+bit[num]>=k)
num-=i;
else x+=bit[num];
}
return num+1;
}
int pre[Mn];
int find(int x) {
return x==pre[x]?pre[x]:pre[x]=find(pre[x]);
}
int num[Mn];
int main() {
int m,c,x,y;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) {
pre[i]=i;
num[i]=1;
}
push(1,n);
int k=n;
for(int i=1;i<=m;i++) {
scanf("%d",&c);
if(c==0) {
scanf("%d%d",&x,&y);
int a=find(x);
int b=find(y);
if(a!=b) {
pre[a]=b;
push(num[a],-1);
push(num[b],-1);
num[b]+=num[a];
num[a]=0;
push(num[b],1);
k--;
}
} else {
scanf("%d",&x);
printf("%d\n",kth(k-x+1));
}
}
return 0;
}