数据结构:线段树

  线段树是一种重要的数据结构,它主要的优势体现在对段的处理上,用于对数据的更新和查询。适用范围比树状数组更广。关于它的函数和离散化可以自己去搜索一下。

  例题:POJ - 2182(http://poj.org/problem?id=2182

  题目大意:有N个牛编号1~N,乱序排成一列,现输入N,以及第2~N个位置上的牛前面有多少头牛小于它的编号,然后正序输出1~N位置上每头牛的编号。如样例:输入5 1 2 1 0。表示五头牛,2~5的位置上分别有1、2、1、0头牛小于位置上牛的编号。输出1~5位置上牛的编号:2 4 5 3 1。

  题目思路:倒着判断,有x头牛编号小于某牛,则这个牛编号就应该位于剩余位置的x+1个位置上,找到该编号,删除,重复上述操作。我们可以在纸上写一下,每个位置的读入的a[i] 为:0 1 2 1 0,现在有1 2 3 4 5这几个位置,然后从后开始读,a[5]是0,位于第1个位置即编号为1,删除编号,剩余编号:2 3 4 5;下一个数a[4]=1,位于第2个位置即编号3,删除编号,剩余:2 4 5;重复,a[3]=2,编号为5,剩余:2 4;a[2] = 1,编号为4,剩余2;a[1]=0,编号为2。于是正序输出:2 4 5 3 1。

  此题可用线段树,若区间长度大于等于查找的位置,则递归左子树,否则递归右子树,直到叶子结点,结点值就是初始编号。

  代码:http://paste.ubuntu.com/16505572/

 1 #include <iostream>
 2 #include <algorithm>
 3 #include <cstdio>
 4 using namespace std;
 5 int a[9000],ans[9000];
 6 struct node
 7 {
 8     int l,r,len;
 9 }s[30000];
10 void build(int root,int l,int r)
11 {
12     s[root].l = l;
13     s[root].r = r;
14     s[root].len = r - l + 1;
15     if(l==r)    return;
16     build(2*root,l,(l+r)/2);
17     build(2*root+1,(l+r)/2+1,r);
18 }
19 int query(int root,int k)
20 {
21     s[root].len--;
22     if(s[root].l == s[root].r)    return s[root].l;
23     if(k<=s[2*root].len)
24         query(2*root,k);
25     else
26         query(2*root+1,k-s[2*root].len);
27 }
28 int main()
29 {
30     int n,i;
31     scanf("%d",&n);
32     for(i=2;i<=n;i++)
33         scanf("%d",&a[i]);
34     a[1]=0;
35     build(1,1,n);
36     for(i=n;i>=1;i--)
37         ans[i] = query(1,a[i]+1);
38     for(i=1;i<=n;i++)
39         printf("%d
",ans[i]);
40 }
原文地址:https://www.cnblogs.com/GodA/p/5509800.html