poj2777——Count Color

题目大意:在一块长L厘米的木板上着色(木板分为长度相等的L块),有T种不同颜色,现在可以有两种操作C和P,一是“C A B C”意思是A到B木板着C颜色,二是“P A B”意思是输出A到B木板上着的不同颜色的种类数,最开始时木板整个被涂上1号颜色。

输入:L  T  O(O是操作个数) (1 <= L <= 100000) (1 <= T <= 30)  (1 <= O <= 100000)

           操作(共O个)

输出:按顺序输出P操作的输出结果

分析:线段树每个结点维护区间着的颜色号。

           首先建好线段树,开始时每个区间都着1号色。然后根据输入判断是C还是P。

           C操作就将A到B着C号色,也就是update线段树:如果当前区间对应要着色的区间,就直接着色返回;如果当前区间本来就已经是C号色则直接返回;如果当前区间只有一种颜色(.num!=-1),就要将它的两个子区间也更新成它的颜色,并且修改它的.num标记为-1,表示当前区间有多种颜色,因为它的某一段(A到B)被着了C号色。接下来就是递归update子区间。

          P操作就查询搜索A到B的颜色个数,也就是search线段树:查询时记录此时线段树中有几种颜色被使用过,vis[]数组就是为了记录这个,我们在搜索到一个只有一个颜色的区间时,就标记这个区间的颜色为1,未使用过的颜色标记为0。接下来就是递归搜索。

          这道题要注意搜不能一直更新到线段树叶节点,更新到符合的区间(两种return情况)就返回,否则会超时。

          有的代码没有用到vis数组,而是直接或运算得出颜色种类数。

代码:转载自https://www.2cto.com/kf/201512/454627.html

#include <iostream>
#include <cstdio>
#include <cstring>
#include
#include <cmath>
#include <queue>
 
using namespace std;
 
struct node
{
     int l,r;
     int num;
} s[ 400010 ];
 
int vis[ 35 ];
 
void InitTree( int l, int r, int k)
{
     s[k].l=l;
     s[k].r=r;
     s[k].num= 1 ;
     int mid=(l+r)/ 2 ;
     if (l==r)
         return ;
     InitTree(l,mid, 2 *k);
     InitTree(mid+ 1 ,r, 2 *k+ 1 );
}
 
void UpdataTree( int l, int r, int c, int k)
{
     if (s[k].l==l&&s[k].r==r)
     {
         s[k].num=c;
         return ;
     }
     if (s[k].num==c)
         return ;
     if (s[k].num!=- 1 ) //如果所查询的区间不是多种颜色
     {
         s[ 2 *k].num=s[k].num; //更新区间的颜色
         s[ 2 *k+ 1 ].num=s[k].num;
         s[k].num=- 1 ; //-1表示该区间有多种颜色
     }
     int mid=(s[k].l+s[k].r)/ 2 ;
     if (l>mid)
         UpdataTree(l,r,c, 2 *k+ 1 );
     else if (r<=mid)
         UpdataTree(l,r,c, 2 *k);
     else
     {
         UpdataTree(l,mid,c, 2 *k);
         UpdataTree(mid+ 1 ,r,c, 2 *k+ 1 );
     }
}
 
void SearchTree( int l, int r, int k)
{
     if (s[k].num!=- 1 )//这段区间只用了一种颜色
     {
         vis[s[k].num]= 1 ;//标记使用过这种颜色
         return ;
     }
     int mid=(s[k].l+s[k].r)/ 2 ;
     if (r<=mid)
         SearchTree(l,r, 2 *k);
     else if (l>mid)
         SearchTree(l,r, 2 *k+ 1 );
     else
     {
         SearchTree(l,mid, 2 *k);
         SearchTree(mid+ 1 ,r, 2 *k+ 1 );
     }
}
 
int main()
{
     int l,t,o,ans;
     while (~scanf( "%d%d%d" ,&l,&t,&o))
     {
         InitTree( 1 ,l, 1 );
         while (o--)
         {
             char ch;
             int a,b,c;
             getchar();
             scanf( "%c" ,&ch);
             if (ch== 'C' )
             {
                 scanf( "%d%d%d" ,&a,&b,&c);
                 if (a>b)
                     swap(a,b);
                 UpdataTree(a,b,c, 1 );
             }
             else
             {
 
                 scanf( "%d%d" ,&a,&b);
                 if (a>b)
                     swap(a,b);
                 memset(vis, 0 ,sizeof(vis));
                 SearchTree(a,b, 1 );
                 ans= 0 ;
                 for ( int i= 1 ; i<=t; i++)//判断所有颜色中使用哪几种就能算出颜色个数了
                     if (vis[i]== 1 )
                         ans++;
                 printf ( "%d\n" ,ans);
             }
         }
     }
     return 0 ;
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值