poj2777(线段树)

题目链接:http://poj.org/problem?id=2777
题目大意:
给定n个板子,和t种颜色,o次操作,每次有两种操作:
C a b x操作:把[a,b]区间内的版子全都涂成x色
P a b操作 :查询[a,b]内有多少种颜色

思路:

首先看n的范围和t的范围
t只有30,比较小,可以用二进制存储每一种颜色,比如010是一种,001又是一种,011就是两种了
也可以开一个k[30],开存储每一种颜色
然后就是着色,就用线段树处理区间问题,注意lazy标签的下传和变量l,r,L,R之间的区分
基本上就是一个板子题

代码:

如果想看骚操作看这里:http://www.oier.cc/poj2777countcolor/

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;
const int maxn=100000+5;
int n,t,o;
int tree[maxn<<2];
int lazy[maxn<<2];
void pushUp(int rt,int l,int r)
{
    tree[rt]=tree[rt<<1] | tree[rt<<1|1];//异或处理==颜色求和
}
void pushDown(int rt,int l,int r)
{
    if(lazy[rt])
    {
        tree[rt<<1]=tree[rt<<1|1]=tree[rt];
        lazy[rt<<1]=lazy[rt<<1|1]=lazy[rt];
        lazy[rt]=0;
    }
}
void build(int rt,int l,int r)
{
    tree[rt]=1;
    if(l==r)
    {
        return;
    }
    int mid=(l+r)>>1;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
}
int query(int rt,int l,int r,int x,int y)
{
    if(x<=l && y>=r)
    {
        return tree[rt];
    }
    pushDown(rt,l,r);
    int m1,m2,mid;
    m1=m2=0;
    mid=(l+r)>>1;
    if(x<=mid) m1=query(rt<<1,l,mid,x,y);
    if(y>mid) m2=query(rt<<1|1,mid+1,r,x,y);
    return m1|m2;
}
void update(int rt,int l, int r,int x,int y,int color)
{
    if(l>=x && r<=y)//到达节点,并且根节点为x
    {
        tree[rt] = 1<< (color-1);
        lazy[rt] = 1;
        return;
    }
    pushDown(rt,l,r);
    int mid=(l+r)>>1;
    if(x<=mid)
        update(rt<<1,l,mid,x,y,color);//往左边查询
    if(y>mid)
        update(rt<<1|1,mid+1,r,x,y,color);//往右边查询
    pushUp(rt,l,r);//更新自己
}
int main()
{
        scanf("%d %d %d",&n,&t,&o);
        build(1,1,n);
//        update(1,1,n,1,n,1);
        char c;
        int l,r,color;
        while(o--)
        {
            getchar();
            scanf("%c",&c);
            if(c=='C')
            {
                scanf("%d%d%d",&l,&r,&color);
                update(1,1,n,l,r,color);
            }

            else
            {
                scanf("%d%d",&l,&r);
                if(l>r)swap(l,r);
                int ans=query(1,1,n,l,r);
                int sum=0;
                while(ans>0)
                {
                    if(ans & 1) sum++;
                    ans>>=1;
                }
                printf("%d\n",sum);
            }

        }

    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值