主要运算:

离散化(可选,当输入数据很大时有用)

建树

插入线段

统计


题目1:所有的数不大于30000的范围内讨论一个问题:现在已知n条线段,把端点依次输入告诉你,然后有m个询问,每个询问输入一个点,要求这个点在多少条线段上出现过;


代码

 1线段树_数据#include <stdio.h>

 2线段树_数据#include <assert.h>

 3线段树_数据

 4线段树_数据//在自然数,且所有的数不大于30000的范围内讨论一个问题:现在已知n条线段,把端点依次输入告诉你,

 5线段树_数据//然后有m个询问,每个询问输入一个点,要求这个点在多少条线段上出现过;

 6线段树_数据

 7线段树_数据#define MAX_NUM_PT 1000

 8线段树_数据#define MAX_TREE_SIZE (MAX_NUM_PT*(MAX_NUM_PT+1)/2)

 9线段树_数据

10线段树_数据struct line

11线段树_#include_11线段树_#include_12线段树_离散化_13{

12线段树_#define_14      int left,right;//左端点、右端点

13线段树_#define_14      int n;//记录这条线段出现了多少次,默认为0, 每个结点的左右儿子位置为2n,2n+1

14线段树_离散化_16}a[MAX_TREE_SIZE];

15线段树_数据

16线段树_数据

17线段树_数据void buildTree(int s,int t, int k)    //要插入的线段的左端点和右端点,插入位置

18线段树_#include_11线段树_#include_12线段树_离散化_13{

19线段树_#define_14    a[k].left = s;

20线段树_#define_14    a[k].right = t;

21线段树_#define_14    a[k].n = 0;

22线段树_#define_14    

23线段树_#define_14    assert(k<=MAX_TREE_SIZE);

24线段树_#define_14

25线段树_#define_14    if(t>s)

26线段树_#include_30线段树_离散化_31    线段树_离散化_13{

27线段树_#define_14        int mid = (s+t)/2;

28线段树_#define_14        

29线段树_#define_14        buildTree(s, mid, 2*k+1);

30线段树_#define_14        buildTree(mid+1, t, 2*k+2);

31线段树_#define_37    }

32线段树_离散化_16}

33线段树_数据

34线段树_数据void insert(int s,int t,int step)//要插入的线段的左端点和右端点、插入位置

35线段树_#include_11线段树_#include_12线段树_离散化_13{

36线段树_#define_14      if (s==a[step].left && t==a[step].right)

37线段树_#include_30线段树_离散化_31      线段树_离散化_13{

38线段树_#define_14            a[step].n++;//插入的线段匹配则此条线段的记录+1

39线段树_#define_14            return;//插入结束返回

40线段树_#define_37      }

41线段树_#define_14      if (a[step].left==a[step].right)   return;//当前线段树的线段没有儿子,插入结束返回

42线段树_#define_14      int mid=(a[step].left+a[step].right)/2;

43线段树_#define_14      if (mid>=t)    insert(s,t,step*2+1);//如果中点在t的右边,则应该插入到左儿子

44线段树_#define_14      else if (mid<s)    insert(s,t,step*2+2);//如果中点在s的左边,则应该插入到右儿子

45线段树_#define_14      else//否则,中点一定在s和t之间,把待插线段分成两半分别插到左右儿子里面

46线段树_#include_30线段树_离散化_31      线段树_离散化_13{

47线段树_#define_14            insert(s,mid,step*2+1);

48线段树_#define_14            insert(mid+1,t,step*2+2);

49线段树_#define_37      }

50线段树_离散化_16}

51线段树_数据

52线段树_数据int FindN(int pt, int k)    //查询数据pt, 位置k

53线段树_#include_11线段树_#include_12线段树_离散化_13{

54线段树_#define_14    int num = a[k].n;

55线段树_#define_14

56线段树_#define_14    assert (pt>=a[k].left && pt<=a[k].right);

57线段树_#define_14

58线段树_#define_14    if (a[k].left<a[k].right)

59线段树_#include_30线段树_离散化_31    线段树_离散化_13{

60线段树_#define_14        assert(a[k*2+1].right<a[k*2+2].left);

61线段树_#define_14

62线段树_#define_14        if(pt<=a[k*2+1].right)

63线段树_#define_14            num += FindN(pt, k*2+1);

64线段树_#define_14

65线段树_#define_14        else if(pt>=a[k*2+1].left)

66线段树_#define_14            num += FindN(pt, k*2+2);

67线段树_#define_37    }

68线段树_#define_14

69线段树_#define_14    return num;

70线段树_离散化_16}

71线段树_数据void main()

72线段树_#include_11线段树_#include_12线段树_离散化_13{

73线段树_#define_14    buildTree(0,4,0);    //根节点区间为[0,4]

74线段树_#define_14    insert(1,3,0);        //插入线段[1,3]

75线段树_#define_14    insert(2,3,0);    

76线段树_#define_14    insert(2,4,0);

77线段树_#define_14

78线段树_#define_14    //统计每个节点的线段覆盖数目

79线段树_#define_14    for (int n=0; n<=4;n++)

80线段树_#include_30线段树_离散化_31    线段树_离散化_13{

81线段树_#define_14        printf("Point %d, num %d\n",n,FindN(n,0));

82线段树_#define_37    }

83线段树_离散化_16}