Interval Tree Topic

今天训练的内容是线段树。

线段树的基本结构,空间大小,常用操作的复杂度已不必多说。主要针对训练中出线的一些问题做一些小的总结

总得来说,对于线段树的编码和调试能力还比较欠缺,这一点希望通过多次的训练来解决

对于各种线段树模型,应用方法则需要经验的积累

 

ZJU 1610:

    线段树的入门题,主要注意的是线段树处理过程中一般如果能覆盖当前区间,操作一般都会终止。这种情况下,如果题意中该区间的操作会影响子区间,那么需要通过一些步骤调整。典型的就是染色。对一个染成同一中颜色的区间的一个子区间染色,我们首先先要将该区间的颜色传递到它的子区间上。见代码line39

  1. #include <iostream>
  2. using namespace std;
  3. const int N = 8010;
  4. struct node
  5. {
  6.     int x, y;
  7.     int color;
  8. }seg[3*N];
  9. int cnt[N];
  10. int num[N];
  11. void build(int root, int x, int y)
  12. {
  13.     seg[root] = (node){x, y, -1};
  14.     if(y > x + 1)
  15.     {
  16.         int mid = (x + y) >> 1;
  17.         build(root * 2, x, mid);
  18.         build(root * 2 + 1, mid, y);
  19.     }
  20. }
  21. void insert(int root, int x, int y, int c)
  22. {
  23.     if(x <= seg[root].x && y >= seg[root].y)
  24.     {
  25.         int j = seg[root].color;
  26.         seg[root].color = c;
  27.     }
  28.     else
  29.     {
  30.         int mid = (seg[root].x + seg[root].y) >> 1;
  31.         if(seg[root].color >= 0)
  32.         {
  33.             seg[root*2].color = seg[root*2 + 1].color = seg[root].color;
  34.             seg[root].color = -1;
  35.         }
  36.         if(x < mid) insert(root * 2, x, y, c);
  37.         if(y > mid) insert(root * 2 + 1, x, y, c);
  38.     }
  39. }
  40. void query(int x)
  41. {
  42.     int i, j;
  43.     
  44.     if(seg[x].color >= 0)
  45.         for(int i = seg[x].x + 1; i <= seg[x].y; i++) cnt[i] = seg[x].color;
  46.     else if(seg[x].x + 1 == seg[x].y) cnt[seg[x].y] = -1;
  47.     else
  48.     {
  49.         query(2*x);
  50.         query(2*x+1);
  51.     }
  52. }
  53.         
  54.         
  55. int main()
  56. {
  57.     int i, j, k, m;
  58.     
  59.     while(scanf("%d",&m) == 1)
  60.     {
  61.         memset(cnt, 0, sizeof(cnt));  
  62.         memset(num, 0, sizeof(num));
  63.               
  64.         build(1, 0, 8000);
  65.         for(; m; m--)
  66.         {
  67.             scanf("%d%d%d",&i, &j, &k);
  68.             insert(1, i, j, k);
  69.         }
  70.         query(1);
  71.         
  72.         i = 1;
  73.         while(i <= 8000)
  74.         {
  75.             while(i <= 8000 && cnt[i]==-1) i++;
  76.             if(i > 8000) break;
  77.             j = i + 1;
  78.             while(j <= 8000 && cnt[j]==cnt[i]) j++;
  79.             num[cnt[i]]++;
  80.             i = j;
  81.         }
  82.         for(i = 0; i <= 8000; i++)
  83.             if(num[i] != 0) printf("%d %d/n",i, num[i]);
  84.         
  85.         printf("/n");
  86.     }
  87.     return 0;
  88. }
  89.             
  90.         
  91.     
  92.     

PKU 2777:

      和上题相似。注意的地方在于。查询的时候,递归结束既可能是因为覆盖了整个区间,也可能是整个区间只有一中颜色。

line 54

  1. #include <iostream>
  2. const int N = 100010;
  3. struct node
  4. {
  5.     int x, y;
  6.     int color;
  7.     bool oneColor;
  8. }seg[N<<2];
  9. int T;
  10. void build(int root, int x, int y)
  11. {
  12.     seg[root] = (node){x, y, 1, true};
  13.     if(x != y)
  14.     {
  15.         int mid = (x + y) >> 1;
  16.         build(root * 2, x, mid);
  17.         build(root * 2 + 1, mid + 1, y);
  18.     }
  19. }
  20. void insert(int root, int x, int y, int c)
  21. {
  22.     if(x <= seg[root].x && y >= seg[root].y){
  23.         seg[root].color = (1<<c);
  24.         seg[root].oneColor = true;
  25.     }
  26.     else
  27.     {
  28.         if(seg[root].oneColor) {
  29.             seg[root*2].color = seg[root*2+1].color = seg[root].color;
  30.             seg[root*2].oneColor = seg[root*2+1].oneColor = true;
  31.             if((1<<c) != seg[root].color) seg[root].oneColor = false;
  32.         }
  33.         
  34.         int mid = (seg[root].x + seg[root].y) >> 1;
  35.         if(x <= mid)
  36.             insert(root*2, x, y, c);
  37.         if(y > mid)
  38.             insert(root*2 + 1, x, y, c);
  39.         
  40.         seg[root].color = seg[root*2].color | seg[root*2+1].color;
  41.     }
  42. }
  43. int query(int root, int x, int y)
  44. {
  45.     if(x <= seg[root].x && y >= seg[root].y)
  46.         return seg[root].color;
  47.     
  48.     if(seg[root].oneColor) return seg[root].color;
  49.     
  50.     else
  51.     {
  52.         int mid = (seg[root].x + seg[root].y) >> 1;
  53.         
  54.         int ans = 0;
  55.         if(x <= mid) ans |= query(root*2, x, y);
  56.         if(y > mid)  ans |= query(root*2 + 1, x, y);
  57.         
  58.         return ans;
  59.     }
  60. }
  61. inline int getNum(int x)
  62. {
  63.     int i = 0;
  64.     while(x != 0) { i += x%2; x/=2;}
  65.     return i;
  66. }
  67. int main()
  68. {
  69.     int n, m;
  70.     int i, j, k;
  71.     
  72.     scanf("%d%d%d",&n, &T, &m);
  73.     build(1, 1, n);
  74.     
  75.     for(; m; m--)
  76.     {
  77.         getchar();
  78.         char ch = getchar();
  79.         if(ch == 'C')
  80.         { 
  81.             scanf("%d%d%d",&i, &j, &k);
  82.             if(i > j) { int t = i; i = j; j = t;}
  83.             insert(1, i, j, k-1);
  84.         }
  85.         else
  86.         {
  87.             scanf("%d%d",&i, &j);
  88.             if(i > j) { int t = i; i = j; j = t;}
  89.             printf("%d/n",getNum(query(1, i, j)));
  90.         }
  91.     }
  92.     return 0;
  93. }
  94.     
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值