POJ 2104 k-th Number (interval K-Large) (square partition, merge tree, partition tree)

Source: Internet
Author: User

Topic Links:

http://poj.org/problem?id=2104

Problem Solving Ideas:

Because the number of queries is large, the naïve method can not be solved within the specified time. Therefore, we should choose a reasonable way to maintain the data in order to efficiently query.

If x is the number of K, then there must be

(1) The number not exceeding x in the interval is not less than K

(2) The number of small to x in the interval is less than k

Therefore, if you can quickly find out the number of numbers not exceeding x in the interval, you can find out the number of K by binary searching X.

Next, let's look at how to calculate the number of x in an interval. If you do not preprocess, then you can only traverse through all the elements.

On the other hand, if the interval is orderly, then the number of numbers not exceeding X can be efficiently calculated by the binary search method. However, if you sort each query one at a time, you simply cannot reduce the complexity. Therefore, it is possible to consider using square and segment trees to solve the problem.

1. Square Partitioning

First, let's look at how to use square partitioning to solve this problem. The sequence of each B-component into each bucket, each of which has a sorted sequence. This can be done if the number of x in an interval is required.

(1) for buckets completely contained within the interval, the binary search method is used to calculate.

(2) For all the buckets are not completely contained within the range of elements, check individually.

If B is set to sqrt (b), the complexity becomes

O ((n/b) logb + b) = O (sqrt (n) logn)

Where the processing of each element as long as O (1) time, and for each bucket of processing requires O (LOGB), so compared to the number of barrels and the amount of elements in the bucket as close as possible, we should be more than the number of buckets to set a bit less than the amount of elements in the bucket, this can make the program more efficient. If you set B to sqrt (NLOGN), the complexity becomes

O ((n/b) logb + b) = O (sqrt (NLOGN))

Next, you just need to do a binary search on X. Because the answer is a certain element in the sequence of a, the binary search needs to execute O (Logn) times. Thus, if B = sqrt (NLOGN), the complexity of the entire algorithm, including preprocessing, is O (Nlogn + msqrt (n) log1.5 (n))

AC Code:

#include <iostream> #include <cstdio> #include <vector> #include <algorithm>using namespace std const int B = 1000;//bucket size const int N = 100005;const int M = 5005;//input int n,m;int a[n];int L[m],r[m],k[m];int nums[n];//pair A Results after sorting vector<int> bucket[n/b];//The result of sorting each bucket is void solve () {for (int i = 0; i < N; i++) {Bucket[i/b].push_b        ACK (A[i]);    Nums[i] = A[i];    } sort (nums,nums+n);    Although there is no sort of bucket for the remainder of each B group, there is no problem for (int i = 0; i < n/b; i++) sort (Bucket[i].begin (), Bucket[i].end ());        for (int i = 0; i < m; i++) {//[l,r] interval k number int l = l[i]-1,r = R[i],k = K[i];        int lb = -1,ub = n-1;            while (ub-lb > 1) {int mid = (lb+ub)/2;            int x = Nums[mid];            int tl = L,TR = r,c = 0;             The portion of the interval is more out of the while (TL < tr && tl% B! = 0) if (a[tl++] <= x) C + +; while (TL < tr && tr% B! = 0) if (a[--TR] <= x) C + +;                Each bucket is calculated while (TL < TR) {int b = tl/b;                c + = Upper_bound (Bucket[b].begin (), Bucket[b].end (), x)-bucket[b].begin ();            TL + = B;            } if (c >= k) UB = mid;        else lb = mid;    } printf ("%d\n", Nums[ub]); }}int Main () {while (~scanf ("%d%d", &n,&m)} {for (int i = 0; i < n; i++) scanf ("%d", &a[i]        );        for (int i = 0; i < m; i++) scanf ("%d%d%d", &l[i],&r[i],&k[i]);    Solve (); } return 0;}

2. Merging trees

Let's consider how to use the segment tree to solve this problem. We maintain the series with line-segment trees. Each node in the segment tree holds the result after the corresponding interval is sorted. The line tree nodes we were exposed to were all values, and this time it was different, and each node saved a sequence.

The process of establishing a segment tree is similar to the merge sort, and the sequence of each node is the combined node of its two sons. The complexity of the achievement is O (NLOGN). Incidentally, this segment tree is the complete embodiment of the merge sort. (merge tree).

To calculate the number of numbers not exceeding x in an interval, simply do the following recursively.

(1) If the given interval is completely disjoint from the current node's interval, then 0 is returned.

(2) If the given interval completely contains the corresponding interval of the current node, then the binary search method is used to find the array saved on the node.

(3) Otherwise the sum of the two sons is calculated recursively.

Since a node of the same depth accesses only a constant number of times, it is possible to find the number of no more than x in the O (log two n) time. So the complexity of the whole algorithm is O (Nlogn + mlog three times Square (n)).

Merge tree
Take 1 5 2 6 3 7 For example:
The recursive process of merge sort is recorded as a merging tree:
[1 2 3 5 6 7]
[1 2 5] [3 6 7]
[1 5] [2] [6 3] [7]
[1] [5] [6][3]
Use the corresponding subscript interval to build the segment tree: (Here the subscript interval corresponds to the original sequence)
[1 6]
[1 3] [4 6]
[1 2] [3] [4 5][6]
[1] [2] [4][5]
Each time I find the K-large number of the [l R] Interval, in [1 2 3 4 5 6 7] The number x to be found in this ordered sequence, and then corresponding to the segment tree to find [l R] in the number of smaller than x, that is, the rank of x. Since any interval in a segment tree is ordered in the merge tree, it is also possible to find the number of smaller numbers in a segment tree by two points in the corresponding merge tree. The time complexity of such a query is log (n) ^2.
It is important to note that when multiple x has the same rank, the largest one should be taken.

AC Code:

#include <iostream> #include <cstdio>using namespace std;const int N = 100005;struct node{int l,r;}    Tree[n<<2];int n,q;int a[n],mer[20][n];void Build (int m,int l,int r,int deep) {tree[m].l = l;    TREE[M].R = R;        if (L = = r) {Mer[deep][l] = num[l];    Return    } int mid = (l+r) >>1;    Build (m<<1,l,mid,deep+1);    Build (m<<1|1,mid+1,r,deep+1);    Merge sort, save int i = L,j = (l+r)/2+1,p = 1 at the time of achievement; while (I <= (l+r)/2 && J <= R) {if (Mer[deep+1][i] > Mer[deep+1][j]) mer[deep][p++] = Mer [Deep+1]        [j + +];    else mer[deep][p++] = mer[deep+1][i++];    } while (I <= (l+r)/2) mer[deep][p++] = mer[deep+1][i++]; while (J <= r) mer[deep][p++] = mer[deep+1][j++];}    int query (int m,int l,int r,int deep,int key) {if (TREE[STEP].R < L | | tree[m].l > R) return 0; if (tree[m].l >= l && TREE[M].R <= R)//find the position of key in the sorted array return Lower_Bound (&mer[deep][tree[m].l],&mer[deep][tree[m].r+1,key)-&mer[deep][tree[m].l]; return query (M<<1,l,r,deep+1,key) +query (M<<1|1,l,r,key);}    int solve (int l,int r,int k) {int low = 1,high = N,mid;        while (Low < high) {mid = (low+high+1) >>1;        int cnt = query (1,l,r,1,mer[1][mid]);        if (CNT <= k) low = mid;    else high = mid-1; } return Mer[1][low];} int main () {while (~scanf ("%d%d", &n,&q)) {for (int i = 1; I <= n; i++) scanf ("%d", &a[i])        ;        Build (1,1,n,1);            while (q--) {int l,r,k;            scanf ("%d%d%d", &l,&r,&k);        printf ("%d\n", Solve (l,r,k-1)); }} return 0;}

3. Partitioning the tree

In fact, the merging tree is in the process of making achievements to save the merge sort, the partition tree is in the process of making achievements to save the fast sorting.

Partition tree
Also take 1 5 2 6 3 7 as an example:
According to the median mid, divide the interval into the number of left subtrees less than or equal to mid, and the number in the right subtree is greater than or equal to mid, getting such a tree:
[1 5 2 6 3 7]
[1 2 3] [5 6 7]
[1 2] [3] [5 6] [7]
[1] [2] [5] [6]
Note to keep the underlying order unchanged
For each interval, use Sum[i] to record the left end of the interval to I have several into the left subtree, that is, several numbers are less than or equal to the mid
Use the corresponding subscript interval to build the segment tree: (Here the subscript interval corresponds to the sorted sequence)
[1 6]
[1 3] [4 6]
[1 2] [3] [4 5][6]
[1] [2] [4][5]
Each time you look up the K-large number of the [l] interval, first look at the current interval [left right] under Sum[r]-SUM[L-1] is less than or equal to K, if it is, then recursively to the Ieft subtree, and continue in [the] [left + sum[l-1], the leftmost + sum[r]-1] to find K large number; otherwise, go to the right subtree, continue in [Mid + L-left + 1-sum[l-1], mid + R-left + 1-sum[r], find the first k-sum[r] + sum[l-1] Large number, such a query as long as the Logn complex Degree


AC Code:

#include <iostream> #include <cstdio> #include <algorithm>using namespace std;const int N = 100005; struct node{int l,r,mid;} Tree[n<<2];int Sa[n],num[20][n],cnt[20][n];//sa is sorted, Num records the sort result of each layer, Cnt[deep][i] represents the first deep layer,    How many of the first I numbers go into the left subtree int n,q;void debug (int d) {for (int i = 1; I <= n; i++) printf ("%d", num[d][i]); printf ("\ n");}    void build (int m,int l,int r,int deep) {tree[m].l = l;    TREE[M].R = R;    if (L = = r) return;    int mid = (l+r) >>1;    int mid_val = Sa[mid],lsum = mid-l+1; for (int i = l; I <= R; i++) if (Num[deep][i] < Mid_val) lsum--;//lsum indicates how many values are needed in the left subtree, int l = l,r    = mid+1;        for (int i = l; I <= R; i++) {if (i = = L) Cnt[deep][i] = 0;        else cnt[deep][i] = cnt[deep][i-1]; if (Num[deep][i] < Mid_val | | (Num[deep][i] = = Mid_val && lsum > 0))            {//Left dial hand tree num[deep+1][l++] = num[deep][i];            cnt[deep][i]++; If(Num[deep][i] = = mid_val) lsum--;    } else num[deep+1][r++] = num[deep][i];    }//debug (deep);    Build (m<<1,l,mid,deep+1); Build (m<<1|1,mid+1,r,deep+1);}    int query (int m,int l,int r,int deep,int k) {if (L = = r) return num[deep][l];    int s1,s2;//s1 to [TREE[STEP].LEFT,L-1] the number of sub-trees to the left if (tree[m].l = = L) S1 = 0;    else S1 = cnt[deep][l-1]; S2 = Cnt[deep][r]-s1;//s2 to the number of left subtrees in [L,r] if (k <= s2)//Zuozi number is greater than K, recursive left subtree return query (M&LT;&LT;1,TREE[M].L+S1,TR    EE[M].L+S1+S2-1,DEEP+1,K);   int B1 = L-1-TREE[M].L+1-S1;//B1 is [TREE[M].L,L-1] the number of sub-trees in the right subtree int b2 = R-L+1-S2;    B2 The number of sub-trees to the right in [l,r] int mid = (TREE[M].L+TREE[M].R) >>1; return query (M&LT;&LT;1|1,MID+1+B1,MID+1+B1+B2-1,DEEP+1,K-S2);} int main () {while (~scanf ("%d%d", &n,&q)) {for (int i = 1; I <= n; i++) {scanf ("%d", &num[            1][i]);        Sa[i] = Num[1][i];        } sort (sa+1,sa+n+1); Build (1, 1,n,1);            while (q--) {int l,r,k;            scanf ("%d%d%d", &l,&r,&k);        printf ("%d\n", Query (1,l,r,1,k)); }} return 0;}


Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.

POJ 2104 k-th Number (interval K-Large) (square partition, merge tree, partition tree)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.