poj-2777(区间线段树,求种类数模板)

题目链接:http://poj.org/problem?id=2777

参考文章:https://blog.csdn.net/heucodesong/article/details/81038360

题目大意:给出T中颜色,可以给一段区域涂色,初始是全为1的颜色,然后有两种操作

(1)C x y z表示将区间x到y的颜色更改为z

(2)P x y 表示查询区间x到y的颜色种类。

题目看起来不符合区间和的条件,但是可以通过二进制转化一下。

初始化肯定都是颜色1,就表示只有一种颜色,然后每次更新颜色时,取这个数的a[x]=1<<(Item-1),a[x]中的1的位置就表示每个颜色的位置

然后pushup操作就改为:a[x]=a[x*2]|a[x*2+1],a[x]中的1的个数就是这个区间颜色的个数。对于Item为什么要-1,其实就是初始颜色时1,就相当于从第0位开始,与数组的0-n-1类似。

(易错:我当时在查询函数中一直出错,但我还没发现,主要是考虑ans1,ans2,ans的初始值是0,这里我已开始写成了1,就错了,

还有ans=ans1|ans2这一步不能少,不然编译会出错,总之,先求出结果再返回。)

 

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
const int maxn = 1e5+10;
int a[maxn*4],b[maxn*4];
void Init()
{
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
}
void pushup(int x)
{
    a[x]=a[x*2]|a[x*2+1];
}
void pushdown(int x)
{
    if(b[x])
    {
        a[x*2]=b[x];
        a[x*2+1]=b[x];
        b[x*2]=b[x];
        b[x*2+1]=b[x];
        b[x]=0;
    }
}
void build(int x,int l,int r)
{
    if(l==r)
    {
        a[x]=1;return ;
    }
    int mid=(l+r)/2;
    build(x*2,l,mid);
    build(x*2+1,mid+1,r);
    pushup(x);
}
void update(int x,int l,int r,int A,int B,int Item)
{
    if(A<=l&&r<=B)
    {
        a[x]=1<<(Item-1);
        b[x]=1<<(Item-1);
        return ;
    }
    int mid=(l+r)/2;
    pushdown(x);
    if(A<=mid) update(x*2,l,mid,A,B,Item);
    if(B>mid) update(x*2+1,mid+1,r,A,B,Item);
    pushup(x);
}
int query(int x,int l,int r,int A,int B)
{
    if(A<=l&&r<=B)
    {
        return a[x];
    }
    int mid=(l+r)/2;
    pushdown(x);
    int ans1=0,ans2=0,ans=0;
    if(A<=mid) ans1=query(x*2,l,mid,A,B);
    if(B>mid) ans2=query(x*2+1,mid+1,r,A,B);
    ans=ans1|ans2;
    return ans;
}
int main(void)
{
    int n,m,t,i,x,y,z;
    while(~scanf("%d%d%d",&n,&t,&m))
    {
        Init();
        build(1,1,n);
        char str[10];
        while(m--)
        {
            scanf("%s",str);
            if(str[0]=='C')
            {
                scanf("%d%d%d",&x,&y,&z);
                if(x>y)
                {
                    int tp=x;
                    x=y;
                    y=tp;
                }
                update(1,1,n,x,y,z);
            }
            else
            {
                scanf("%d%d",&x,&y);
                if(x>y)
                {
                    int tp=x;
                    x=y;
                    y=tp;
                }
                int cnt=0,ans=query(1,1,n,x,y);
                while(ans)
                {
                    if(ans&1) cnt++;
                    ans>>=1;
                }
                printf("%d\n",cnt);
            }
        }
    }
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/2018zxy/p/10139990.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值