poj 2104 归并树

来源:互联网 发布:js动态设置div内容居中 编辑:程序博客网 时间:2024/05/01 04:46

每次查找二分出某个数,logn时间在树中找到它的区间,二分找比它小的数的个数,三次二分= (log n)^3

解决的问题:查询某个区间内第k大的数

值得注意的是:

1.归并树,划分树都只能解决元素不重复的情况

2.多个x有相同rank的时候取最大的x

这些相同rank的数组成一个序列A1,A2,……An,之间两两不同,因为没有重复元素

若答案不是An而是Ai(1<=i<n),则An的rank应该是rank(An)+1,这与已知矛盾



#include <iostream>#include <cstring>#include <cstdio>#include <cstdlib>#include <algorithm>using namespace std;#define N 100500#define M 5500struct node{int l,r,rank;}tree[3*N];int ha[20][N];int n,m;void build(int pos,int l,int r,int rank){tree[pos].rank=rank;tree[pos].l=l;tree[pos].r=r;if(l==r){ha[rank][l]=ha[0][l];return;}int mid=(l+r)>>1;build(pos*2,l,mid,rank+1);build(pos*2+1,mid+1,r,rank+1);int i=l,j=mid+1,cnt=l;while(i<=mid&&j<=r){if(ha[rank+1][i]<ha[rank+1][j])ha[rank][cnt++]=ha[rank+1][i++];else ha[rank][cnt++]=ha[rank+1][j++];}while(i<=mid) ha[rank][cnt++]=ha[rank+1][i++];while(j<=r) ha[rank][cnt++]=ha[rank+1][j++];}int query(int pos,int l,int r,int x){if(tree[pos].l==l&&tree[pos].r==r){int num=lower_bound(ha[tree[pos].rank]+tree[pos].l,ha[tree[pos].rank]+tree[pos].r+1,x)-(ha[tree[pos].rank]+tree[pos].l);return num;}int mid=(tree[pos].l+tree[pos].r)>>1;int c1=0,c2=0;if(r<=mid)c1=query(pos*2,l,r,x);else if(l>mid)c2=query(pos*2+1,l,r,x);else{c1=query(pos*2,l,mid,x);c2=query(pos*2+1,mid+1,r,x);}return c1+c2;}int main (){while(scanf("%d%d",&n,&m)!=EOF){for(int i=1;i<=n;++i)scanf("%d",&ha[0][i]);build(1,1,n,0);int ll,rr,k;while(m--){scanf("%d%d%d",&ll,&rr,&k);int l=1,r=n,mid;int res,re;while(l<=r){mid=(l+r)/2;res=query(1,ll,rr,ha[0][mid])+1;if(res<=k){re=mid;l=mid+1;}else r=mid-1;  // 为了返回有相同排位的数中最大的一个,二分细节中很多要注意}printf("%d\n",ha[0][re]);}}//system("pause");return 0;}


原创粉丝点击