线段树

线段树

 
线段树的构造思想 
线段树是一棵二叉树,树中的每一个结点表示了一个 区间[a,b]。每一个叶子节点表示了一个单位区间。对于每一个非叶结点所表示的结点[a,b],其左儿子表示的区间为[a,(a+b)/2],右儿子表示的区间为[(a+b)/2,b]。 
例如: 

线段树的运用 
线段树的每个节点上往往都增加了一些其他的域。在这些域中保存了某种动态维护的信息,视不同情况而定。这些域使得线段树具有极大的灵活性,可以适应不同的需求。 

例1:求覆盖线段的总长度 
      [10000,22000]   [30300,55000]   [44000,60000]   [55000,60000] 
排序得10000,22000,30300,44000,55000,60000 
对应得     1,   2,    3,    4,    5,    6 
        [1,2]            [3,5]           [4,6]          [5,6] 

线段树做法: 







例2: http://acm.pku.edu.cn/JudgeOnline/problem?id=2528 
题意:贴海报,输出可以看到的个数. 
Java代码   收藏代码
  1. //贴海报,输出没有被覆盖的个数  
  2. //可以改成cpp试试  
  3. #include<stdio.h>  
  4. struct node  
  5. {  
  6.     int l,r; //左右孩子的编号  
  7.     int st,mi,en;  
  8.     int id;  
  9. };  // 线段树简单一维  
  10. const int maxN = 50000002//线段树的节点个数  
  11. const int maxL = 10000020//台阶的宽度上限  
  12.   
  13. node segment_tree[maxN]; //保存着线段树的所有节点  
  14. #define tree segment_tree  
  15. int root, ptr;  
  16. void insert(int cr, int start, int end, int color) //插入到指定区域,同时初始化沿途的所有节点  
  17. {  
  18.     if(start >= end) //不符合输入要求  
  19.         return;  
  20.     if(tree[cr].st == start && tree[cr].en == end) //输入区间正好等于节点的表示区间  
  21.     {  
  22.         tree[cr].id = color; //这个区间属于该海报  
  23.         return;  
  24.     }  
  25.     int mid = (tree[cr].st + tree[cr].en) / 2;  
  26.     if(tree[cr].l == 0//意味着还没有初始化孩子结点  
  27.     {  
  28.         //ptr代表节点的编号  
  29.         tree[cr].l = ptr++;  
  30.         tree[tree[cr].l].l = tree[tree[cr].l].r = 0;  
  31.         tree[tree[cr].l].id = -1;  
  32.         tree[tree[cr].l].st = tree[cr].st, //这里对左右孩子的范围进行初始化  
  33.         tree[tree[cr].l].en = mid;  
  34.     }  
  35.     if(tree[cr].r == 0)  
  36.     {  
  37.         tree[cr].r = ptr++;  
  38.         tree[tree[cr].r].l = tree[tree[cr].r].r = 0;  
  39.         tree[tree[cr].r].id = -1;  
  40.         tree[tree[cr].r].st = mid,  
  41.         tree[tree[cr].r].en = tree[cr].en;  
  42.     }  
  43.   
  44.     if(tree[cr].id != 0//之后的子区间肯定都属于该海报  
  45.     {  
  46.         tree[tree[cr].l].id = tree[tree[cr].r].id = tree[cr].id;  
  47.         tree[cr].id = 0;  
  48.     }  
  49.   
  50.     if(start >= mid){  
  51.         insert(tree[cr].r, start, end, color);  
  52.         return;  
  53.     }  
  54.     if(end <= mid){  
  55.         insert(tree[cr].l, start, end, color);  
  56.         return;  
  57.     }  
  58.     insert(tree[cr].l, start, mid, color);  
  59.     insert(tree[cr].r, mid, end, color);  
  60. }  
  61.   
  62.   
  63. char exist[10001];  
  64. void trail(int cr) //统计可以看见的节点编号  
  65. {  
  66.     if(cr == 0 || tree[cr].id == -1)  
  67.         return;  
  68.     exist[tree[cr].id] = 1//id不为0,意味着只有它可见,但之后的节点都看不见了.  
  69.     if(tree[cr].id != 0//不为0意味着后面的区域都要被覆盖.  
  70.         return;  
  71.     trail(tree[cr].l);  
  72.     trail(tree[cr].r);  
  73. }  
  74.   
  75. //初始化跟节点  
  76. void init()  
  77. {  
  78.     root = 1;  
  79.     tree[root].l = tree[root].r = tree[root].id = 0;  
  80.     tree[root].st = 1, tree[root].en = maxL, tree[root].mi = (1 + maxL)/2;  
  81.     ptr = 2;  
  82. }  
  83.   
  84. int main()  
  85. {  
  86.     int test,n,i,l,r;  
  87.     scanf("%d", &test);  
  88.     while(test--)  
  89.     {  
  90.         init();  
  91.         scanf("%d",&n);  
  92.         for(i = 1; i <= n; i++)  
  93.         {  
  94.             scanf("%d%d",&l,&r);  
  95.             insert(1, l, r+1, i); //从根节点开始插入  
  96.         }  
  97.         for(i = 1; i <= n; i++)  
  98.             exist[i] = 0;  
  99.         trail(1);  
  100.         int ans = 0;  
  101.         for(i = 1; i <= n; i++)  
  102.             if(exist[i])  
  103.                 ans++;  
  104.         printf("%d\n",ans);  
  105.     }  
  106.     return 0;  
  107. }  
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值