G - The Famous ICPC Team Agai(hdu 4251)
题目要求:给出区间(区间长度为奇数odd),的中间值。用了划分树
http://blog.csdn.net/shiqi_614/article/details/8041390 划分树题解
http://blog.csdn.net/qq172108805/article/details/7761967 划分树题解
/*
求区间中间值
可以转化为求kth值 所以用了划分树
*/
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<math.h>
#define MAX 100009
using namespace std;
struct node {
int num[MAX];//num记录元素所在区间的当前位置进入左子树的个数
int val[MAX];//val记录第k层当前位置元素的值N
}t[40]; //(logn)
int n;
int srted[MAX];
void build(int l,int r,int d) { //建树 此树并非由节点构成 而是由数组的一段构成 如:d层的l~r是一个节点
if(l==r) return;
int mid=(l+r)>>1;//取中间那个
int midd=srted[mid];
int same=mid-l+1,samed=0,zn=l-1,yn=mid,i;//same初识化为左子树元素个数
//下面减去比midd小的(一定会进入左孩子里边) 剩下的就是==midd并且要进入左孩子的个数
//samed是已经插入的数目
//zn、yn是左右孩子的开始位置-1,下面会把元素分到两个子树的区域里边
for(i=l; i<=r; ++i)
if(t[d].val[i]<midd) --same;
for(i=l; i<=r; ++i) { //有点像快排 大的放到后边 小的放前边 相等的看情况
if(i==l) t[d].num[i]=0;
else t[d].num[i]=t[d].num[i-1];
if(t[d].val[i]<midd) {
++t[d].num[i];//这里是统计从l到i有多少元素进入了左子树 这是划分树主要用到的数据
t[d+1].val[++zn]=t[d].val[i];
} else if(t[d].val[i]>midd) { //进入右子树
t[d+1].val[++yn]=t[d].val[i];
} else {
if(samed<same) {//左子树还差same个 放左孩子里边
++samed;
++t[d].num[i];
t[d+1].val[++zn]=t[d].val[i];
} else //左子树已经放满,则放入右子树
t[d+1].val[++yn]=t[d].val[i];
}
}
build(l,mid,d+1);//建左右子树
build(mid+1,r,d+1);
}
int query(int a,int b,int k,int l,int r,int d)//在d层[l,r]的节点里查找[a,b]中的第k大值
{
if(a==b) return t[d].val[a];
int mid=(l+r)>>1;
int sx=t[d].num[a-1],sy=t[d].num[b];
if(a-1<l) sx=0;
if(sy-sx>=k)//[a,b]进入左子树的元素>=k,由于进入时是按顺序进入的,那么左子树的前sx个不在[a,b]之间
return query(l+sx,l+sy-1,k,l,mid,d+1);
else
{
int s1=(a==1?0:a-l-sx);//a前面进入右子树的元素的个数
int s2=(b-a+1)-(sy-sx);//[a,b]之间进入右子树的元素的个数?
int nk=k-(sy-sx);//前(sy-sx)大的元素在左子树里 剩下的在右子树里边找
return query(mid+1+s1,mid+s1+s2,nk,mid+1,r,d+1);//mid->mid+s1之前的不是[a,b]之间的
}
}
int main() {
int cas=1;
while(~scanf("%d",&n)){
printf("Case %d:\n",cas++);
for(int i=1;i<=n;i++){
scanf("%d",&srted[i]);
t[0].val[i]=srted[i];
}
sort(srted+1,srted+n+1);
build(1,n,0);
int m;
scanf("%d",&m);
int a,b;
while(m--){
scanf("%d %d",&a,&b);
int ans=query(a,b,(a+b)/2-a+1,1,n,0);
printf("%d\n",ans);
}
}
return 0;
}