题目:http://poj.org/problem?id=2104 借此题学习了一下划分树 划分树定义: 他的每个节点保存【l, r】区间的所有元素,元素的排列顺序与输入的顺序相同,但是其两个子树的元素是所有元素排序后, 有(l+r)/2个元素进入左子树,其余的进入右子树,同时 维护一个num[]变量, num[i]表示l->i中, 有多少个元素进入了左子树。红色代表进入左子树的元素。
#include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> using namespace std; const int maxn=100000; struct TreeNode { int var[maxn+10]; int num[maxn+10]; }tn[30]; int sorted[maxn+10]; int n, m, a, b, c; void BuildTree(int v, int left, int right) { if (left==right) return; int mid=(left+right)>>1; int lchild=left, rchild=mid+1; int isame=mid-left+1, same=0; for (int i=left; i<=right; i++) if (tn[v].var[i]<sorted[mid]) isame--; for (int i=left; i<=right; i++) { if (i==left) tn[v].num[i]=0; else tn[v].num[i]=tn[v].num[i-1]; if (tn[v].var[i]<sorted[mid]) { tn[v].num[i]++; tn[v+1].var[lchild++]=tn[v].var[i]; } else if (tn[v].var[i]>sorted[mid]) tn[v+1].var[rchild++]=tn[v].var[i]; else { if (same<isame) { same++; tn[v].num[i]++; tn[v+1].var[lchild++]=tn[v].var[i]; } else tn[v+1].var[rchild++]=tn[v].var[i]; } } BuildTree(v+1, left, mid); BuildTree(v+1, mid+1, right); } //在区间【l, r】中查找第K大元素 //1.如果tn[v].num[r]-tn[v].num[l-1]>=k,也就是说在区间【l, r】中已经有超过k个元素进入到左子树了,并且其顺序不变,所以 //在其左子树中查找,并且其区间变成【left+tn[v].num[l-1], left+tn[v].num[r]-1】 //2.如果tn[v].num[r]-tn[v].num[l-1]<k,也就是说在区间【l, r】中少于K个元素进入左子树,那么就要在右子树中查找第k-s(s代表进入左子树的元素个数)个元素。 //其区间变为【mid+【left, l-1】中分到右子树中元素的个数+1, mid+【l, r】中分到右子树中元素的个数】。 int Query(int l, int r, int k, int v, int left, int right) { if (left==right) return tn[v].var[l]; int mid=(left+right)>>1; int s, ss, b, bb; if (l==left) { s=tn[v].num[r]; ss=0; } else { s=tn[v].num[r]-tn[v].num[l-1]; ss=tn[v].num[l-1]; } if (s>=k) { l=left+ss; r=left+ss+s-1; return Query(l, r, k, v+1, left, mid); } else { b=l-left-ss; bb=r-l+1-s; l=mid+b+1; r=mid+b+bb; return Query(l, r, k-s, v+1, mid+1, right); } } int main() { //freopen("in.txt", "r", stdin); while (scanf("%d %d", &n, &m)==2) { for (int i=1; i<=n; i++) { scanf("%d", &sorted[i]); tn[1].var[i]=sorted[i]; } sort(sorted+1, sorted+n+1); BuildTree(1, 1, n); for (int i=0; i<m; i++) { scanf("%d %d %d", &a, &b, &c); printf("%d\n", Query(a, b, c, 1, 1, n)); } } return 0; }
PKU 2104 K-th Number
最新推荐文章于 2025-01-14 11:30:45 发布