POJ 2104 劃分樹模板題
阿新 • • 發佈:2019-01-30
給出n,m
n個數字
m次詢問,每次詢問(l,r)區間的第k小的數
劃分樹模板 mark一下
#include "stdio.h" #include "string.h" #include "algorithm" using namespace std; int a[100010],as[100010]; int tree[20][100010];// 記錄第i層元素序列 int sum[20][100010];// 記錄第i層的1~j劃分到左子樹的元素個數(包括j) void build(int c,int l,int r) { int mid,i; int lm; // 記錄左區間共有多少個數=as{mid] int lp; // 左區間的mark int rp; // 右區間的mark mid=(l+r)/2; lm=mid-l+1; lp=l; rp=mid+1; for (i=l;i<=mid;i++) if (as[i]<as[mid]) lm--;//先假設左邊的(mid - l + 1)個數都等於as[mid],然後把實際上小於as[mid]的減去 for (i=l;i<=r;i++) { if (i==l) sum[c][i]=0; else sum[c][i]=sum[c][i-1]; if (tree[c][i]==as[mid]) { if (lm) { lm--; sum[c][i]++; tree[c+1][lp++]=tree[c][i]; } else tree[c+1][rp++]=tree[c][i]; } else if (tree[c][i]<as[mid]) { sum[c][i]++; tree[c+1][lp++]=tree[c][i]; } else tree[c+1][rp++]=tree[c][i]; } if (l==r) return ; build(c+1,l,mid); build(c+1,mid+1,r); } int query(int c,int l,int r,int ql,int qr,int k)// 在l-r區間內的 ql-qr區間中的第K小的數 { int s;//[l, ql)內將被劃分到左子樹的元素數目 int ss;//[ql, qr]內將被劃分到左子樹的元素數目 int mid=(l+r)/2; if (l==r) return tree[c][l]; if (l==ql) { s=0; ss=sum[c][qr]; } else { s=sum[c][ql-1]; ss=sum[c][qr]-s; } if (k<=ss) return query(c+1,l,mid,l+s,l+s+ss-1,k); else return query(c+1,mid+1,r,mid-l+1+ql-s,mid-l+1+qr-s-ss,k-ss); } int main() { int n,m,i,l,r,k; while (scanf("%d%d",&n,&m)!=EOF) { for (i=1;i<=n;i++) { scanf("%d",&a[i]); tree[0][i]=as[i]=a[i]; } sort(as+1,as+1+n); build(0,1,n); while (m--) { scanf("%d%d%d",&l,&r,&k); printf("%d\n",query(0,1,n,l,r,k)); } } return 0; }