pku 2777 Count Color 解体报告

这到题的题意很明确,给你L长的离散的带子,初始时都图色1。然后给出O个查询和更新条件。对于这样的题一般用线段树比较好做,而且效率很好。由于颜色比较少,可以用二进制的形式来表示(即所有出入的颜色值都要做这样的处理,把它转化为1左移这么多位所对应的值,即1<<(c-1)),这样在进行颜色合并时就方便多了,直接 A|B。这点搞清楚后,线段树就好写了。
这是我写的代码。
 1 
 2  #include < iostream >
 3  #include < algorithm >
 4  using   namespace  std;
 5  #define  MAXN 100001
 6 
 7  struct  Seg_Tree{
 8    Seg_Tree  * leftptr, * rightptr;
 9     int  left,right;
10     int  col;
11  } * Root;
12 
13  int  L,T,O,cnt;
14  int  nmem;
15  Seg_Tree mem[MAXN * 10 ];
16 
17  Seg_Tree *  CreateNode(){
18    Seg_Tree *  p =& mem[nmem ++ ];
19    memset(p, 0 , sizeof (Seg_Tree));
20     return  p;
21  }
22 
23  Seg_Tree *  CreateTree( int  s, int  e){
24    Seg_Tree *  root = CreateNode();
25    root -> left = s;
26    root -> right = e;
27     if (s != e){
28       int  mid = (s + e) / 2 ;
29      root -> leftptr = CreateTree(s,mid);
30      root -> rightptr = CreateTree(mid + 1 ,e);
31    }
32     return  root;
33  }
34 
35  bool  odd( int  n){ // 判断奇偶的,其实就判断是不是只有一种颜色。
36     return  (n & (n - 1 )) == 0 ;
37  }
38 
39  void  UpdateTree(Seg_Tree *  root, int  s, int  e, int  c){
40       if (s <= root -> left && e >= root -> right){
41        root -> col = c;
42         return ;
43      }
44       if (root -> col == c)  return ;
45       if (odd(root -> col)){
46        root -> leftptr -> col = root -> col;
47        root -> rightptr -> col = root -> col;
48      }
49       int  mid = (root -> left + root -> right) / 2 ;
50       if (s <= mid) UpdateTree(root -> leftptr,s,e,c);
51       if (e > mid) UpdateTree(root -> rightptr,s,e,c);
52      root -> col = root -> leftptr -> col | root -> rightptr -> col;
53  }
54  void  Query(Seg_Tree *  root, int  s, int  e, int   & cnt){
55       if (s <= root -> left && e >= root -> right){
56          cnt = cnt | root -> col;
57           return ;
58      }
59       if (odd(root -> col)){
60          cnt = cnt | root -> col;
61           return ;
62      }
63     int  mid = (root -> left + root -> right) / 2 ;
64     if (s <= mid) Query(root -> leftptr,s,e,cnt);
65     if (e > mid) Query(root -> rightptr,s,e,cnt);
66  }
67  int  cal( int  n){
68     int  cnt = 0 ;
69     while (n > 0 ){
70       if (n % 2 ) cnt ++ ;
71      n >>= 1 ;
72    }
73     return  cnt;
74  }
75  int  main(){
76    nmem = 0 ;
77    scanf( " %d%d%d " , & L, & T, & O);
78    Root = CreateTree( 1 ,L);
79    UpdateTree(Root, 1 ,L, 1 );
80     char  cmd;
81     int  s,e,c;
82     while (O -- ){
83      scanf( "  %c " , & cmd);
84       if (cmd == ' C ' ){
85        scanf( " %d%d%d " , & s, & e, & c);
86         if (s > e) swap(s,e);
87        UpdateTree(Root,s,e, 1 << (c - 1 ));
88      }
89       else {
90        cnt = 0 ;
91        scanf( " %d%d " , & s, & e);
92         if (s > e) swap(s,e);
93        Query(Root,s,e,cnt);
94        printf( " %d\n " ,cal(cnt));
95      }
96    }
97     return   0 ;
98  }
99 

转载于:https://www.cnblogs.com/saintqdd/archive/2007/11/04/948622.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值