poj 2104
区间第K小 刚刚学的划分树
感觉树的作用就是 n^2 -> n logn
分治一下 划分成左右2个子树 然后小的左边 大的右边
#include <iostream> #include<string.h> #include<stdio.h> #include<algorithm> #include<string> #include<math.h> using namespace std ; #define e 2.7182818284 #define LL __int64 #define MAXN 200010 #define inf 1000000000 struct node { int val[MAXN];//当前这一层的第i个位置的值 int num[MAXN];//到i这个位子应该进入左子树的数目 }t[20]; //划分成左右的化不会超过20层 int sorted[MAXN]; //排序后的数组 void Build(int l,int r,int ind) //建树 左右区间 然后层数 { if(l==r) return ; int mid=(l+r)>>1; int lsame = mid-l+1,same=0,ln=l,rn=mid+1;//lsame 代表到左子树的数目 下面有用 其实是算出到左边满了没有 for(int i=l;i<=r;i++) if(t[ind].val[i]<sorted[mid]) //小的话显然是要去的 lsame--; for(int i=l;i<=r;i++) { if(i==l) t[ind].num[i]=0; else t[ind].num[i]+=t[ind].num[i-1]; if(t[ind].val[i]<sorted[mid]) t[ind].num[i]++,t[ind+1].val[ln++]=t[ind].val[i];//小的话去左边 然后左子树的值附上 else if(t[ind].val[i]>sorted[mid]) t[ind+1].val[rn++]=t[ind].val[i]; else { same++; if(lsame>=same) t[ind].num[i]++,t[ind+1].val[ln++]=t[ind].val[i]; //这边是左边还能去 else t[ind+1].val[rn++] = t[ind].val[i]; } } Build(l,mid,ind+1); Build(mid+1,r,ind+1); } int ques(int st, int ed, int k, int l,int r, int ind) { if(l==r) return t[ind].val[l]; int lx,ly,rx,ry,mid = (l + r)>>1; if(st == l) lx = 0, ly = t[ind].num[ed]; else lx = t[ind].num[st - 1],ly = t[ind].num[ed] - t[ind].num[st - 1];
if(ly >= k) //左子树大了 { st = l + lx; ed = l + lx + ly -1; return ques(st,ed,k,l,mid, ind+1); } else //去掉左子树的那段 从右边那段开始 { rx = st - 1 - l + 1 - lx; ry = ed - st + 1 - ly; st = mid + 1 + rx; ed = mid + 1 + rx + ry - 1; return ques(st,ed,k - ly, mid + 1,r,ind + 1); } } int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&sorted[i]); t[0].val[i]=sorted[i]; } sort(sorted+1,sorted+n+1); Build(1,n,0); while(m--) { int a,b,c; scanf("%d%d%d",&a,&b,&c); int ans=ques(a,b,c,1,n,0); printf("%d\n",ans); } return 0; }
posted on 2017-03-04 11:08 HelloWorld!--By-MJY 阅读(125) 评论(0) 编辑 收藏 举报