poj 2985 线段树求第k大的数

树状数组实现好了之后,改用线段树也实现了一下,接下来再用各种树实现,继续学习!!

View Code
#include<cstdio>
#include<cstring>
const int maxn = 222222;
#define mid (l+r)>>1
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
int sum[maxn<<2];//记录有几个点的范围在节点的范围内
int a[maxn],p[maxn];
int n;
/*void pushup(int rt){
sum[rt]=sum[rt<<1]+sum[rt<<1|1];
}
*///在这里 pushup操作不需要,因为更新操作是从上往下进行的,到哪个节点就更新哪个节点
void build(int l,int r,int rt){
if(l==1) sum[rt]=n;
else sum[rt]=0;
if(l==r) return ;
int m=mid;
build(lson);
build(rson);
}
void update(int l,int r,int rt,int val,bool flag){
if(!flag) sum[rt]--;
else sum[rt]++;
int m=mid;
if(l==r) return ;
if(val<=m) update(lson,val,flag);
else update(rson,val,flag);
// pushup(rt);
}
int find(int x){
return x==p[x] ? x : p[x]=find(p[x]);
}
void query(int l,int r,int rt,int k){
if(l==r) {
printf("%d\n",l);
return ;
}
int m=mid;
if(k<=sum[rt<<1|1]) query(rson,k);//右子树有大于等于k个数,第k个数肯定在右边
else query(lson,k-sum[rt<<1|1]);
}
int main(){
int i,m,q,x,y,k;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++) {
a[i]=1; p[i]=i;
}
build(1,n,1);
for(i=1;i<=m;i++) {
scanf("%d",&q);
if(q==0){
scanf("%d%d",&x,&y);
x=find(x);
y=find(y);
if(x==y) continue;
update(1,n,1,a[x],false);
update(1,n,1,a[y],false);
update(1,n,1,a[x]+a[y],true);
p[y]=x;
a[x]+=a[y];
}
else {
scanf("%d",&k);
query(1,n,1,k);
}
}
return 0;
}

 

你可能感兴趣的:(poj)